Logo Search packages:      
Sourcecode: kdenetwork version File versions

void OscarSocket::parseIM ( Buffer &  inbuf  )  [private]

Parses an incoming IM

Definition at line 331 of file oscar_fam04.cpp.

References findTLV(), gotDirectIMRequest(), gotFileSendRequest(), parseCap(), parseServerIM(), parseSimpleIM(), parseUserInfo(), and OscarConnection::protocolError().

Referenced by slotRead().

{
      QByteArray cook(8);
      //This is probably the hardest thing to do in oscar
      //first comes an 8 byte ICBM cookie (random)
      // from icq docs:
      // this value is
      // ((time(NULL) - (8*60*60)) + DayOfWeek*60*60*24)) * 1500
      inbuf.getBlock(8);

      // Channel ID.
      //
      // Channel 0x0001 is the message channel.  There are
      // other channels for things called "rendevous"
      // which represent chat and some of the other new
      // features of AIM2/3/3.5.
      //
      // Channel 0x0002 is the Rendevous channel, which
      // is where Chat Invitiations and various client-client
      // connection negotiations come from.
      //
      // Channel 0x0004 is used for ICQ authorization, or
      // possibly any system notice.
      WORD channel = inbuf.getWord();

      // Extract the standard user info block.
      //
      // Note that although this contains TLVs that appear contiguous
      // with the TLVs read below, they are two different pieces.  The
      // userinfo block contains the number of TLVs that contain user
      // information, the rest are not even though there is no separation.
      //
      // That also means that TLV types can be duplicated between the
      // userinfo block and the rest of the message, however there should
      // never be two TLVs of the same type in one block.
      UserInfo u;
      parseUserInfo(inbuf, u);

      switch(channel)
      {
            case MSGFORMAT_SIMPLE: //normal IM
            {
                  parseSimpleIM(inbuf, u);
                  break;
            }; // END MSGFORMAT_SIMPLE


            case MSGFORMAT_ADVANCED: //AIM rendezvous, ICQ advanced messages
            {
#if 0
                  if (mIsICQ) // TODO: unify AIM and ICQ in this place
#endif
                  {
                        kdDebug(14150) << k_funcinfo << "IM received on channel 2 from '" << u.sn << "'" << endl;
                        TLV tlv5tlv = inbuf.getTLV();
                        //kdDebug(14150) << k_funcinfo << "The first TLV is of type " << tlv5tlv.type << endl;
                        if (tlv5tlv.type != 0x0005)
                        {
                              kdDebug(14150) << k_funcinfo <<
                                    "Aborting because first TLV != TLV(5)" << endl;
                              break;
                        }

                        Buffer tlv5(tlv5tlv.data, tlv5tlv.length);

                        /*WORD ackType =*/ tlv5.getWord();
                        DWORD msgTime = tlv5.getDWord();
                        DWORD msgRandomId = tlv5.getDWord();
                        char *capData = tlv5.getBlock(16);
                        DWORD capFlag = parseCap(capData);
                        delete [] capData;

                        QPtrList<TLV> lst = tlv5.getTLVList();
                        lst.setAutoDelete(TRUE);

                        TLV *msgTLV = findTLV(lst,0x2711);  //message tlv
                        if(!msgTLV)
                        {
                              kdDebug(14150) << k_funcinfo <<
                                    "Aborting because TLV(10001) wasn't found (no message?)" << endl;
                              break;
                        }

                        switch(capFlag)
                        {
                              case CAP_ISICQ:
                                    // found in direct-connection stuff?
                                    break;

                              case CAP_ICQSERVERRELAY:
                              {
                                    Buffer messageBuf(msgTLV->data, msgTLV->length);
                                    WORD len = messageBuf.getLEWord();
                                    if (len != 0x001b)
                                          kdDebug(14150) << k_funcinfo << "wrong len till SEQ1!" << endl;
                                    WORD tcpVer = messageBuf.getLEWord();
                                    //kdDebug(14150) << k_funcinfo << "len=" << len << ", tcpver=" << tcpVer << endl;
                                    char *cap=messageBuf.getBlock(16);
                                    WORD unk1 = messageBuf.getLEWord();
                                    DWORD unk2 = messageBuf.getLEDWord();
                                    BYTE unk3 = messageBuf.getLEByte();
                                    WORD seq1 = messageBuf.getLEWord();


                                    Buffer ack; // packet sent back as acknowledgment
                                    ack.addSnac(4, 11, 0, 0);
                                    ack.addDWord(msgTime);
                                    ack.addDWord(msgRandomId);
                                    ack.addWord(0x0002); // type-2 ack
                                    ack.addBUIN(u.sn.latin1());
                                    ack.addWord(0x0003); // unknown
                                    ack.addLEWord(len);
                                    ack.addLEWord(tcpVer);
                                    ack.addString(cap, 16);
                                    ack.addLEWord(unk1);
                                    ack.addLEDWord(unk2);
                                    ack.addLEByte(unk3);
                                    ack.addLEWord(seq1);

                                    parseAdvanceMessage(messageBuf, u, ack);
                                    break;
                              }

                              default: // TODO
                              {
                                    kdDebug(14150) << k_funcinfo <<
                                          "Unsupported TYPE-2 message, capability flag is " <<
                                          capFlag << endl;
                                    break;
                              }
                        } // END switch(capFlag)

                        break;
                  }
#if 0
                  else
                  {

                        // ===========================================
                        // TODO: unify AIM and ICQ parts
                        // ===========================================

                        unsigned int remotePort = 0;
                        QString qh;
                        QString message;
                        WORD msgtype = 0x0000; //used to tell whether it is a direct IM requst, deny, or accept
                        DWORD capflag = 0x00000000; //used to tell what kind of rendezvous this is
                        /*OncomingSocket *sockToUse;*/ //used to tell which listening socket to use
                        QString fileName; //the name of the file to be transferred (if any)
                        long unsigned int fileSize = 0; //the size of the file(s) to be transferred

                        kdDebug(14150) << k_funcinfo << "IM received on channel 2 from " << u.sn << endl;
                        TLV tlv = inbuf.getTLV();
                        kdDebug(14150) << k_funcinfo << "The first TLV is of type " << tlv.type;
                        if (tlv.type == 0x0005) //connection info
                        {
                              Buffer tmpbuf(tlv.data, tlv.length);
                              //embedded in the type 5 tlv are more tlv's
                              //first 2 bytes are the request status
                              // 0 - Request
                              // 1 - Deny
                              // 2 - Accept
                              msgtype = tmpbuf.getWord();

                              //next comes the cookie, which should match the ICBM cookie
                              char *c = tmpbuf.getBlock(8);
                              cook.duplicate(c,8);
                              delete [] c;

                              //the next 16 bytes are the capability block (what kind of request is this?)
                              char *cap = tmpbuf.getBlock(0x10);
                              capflag = parseCap(cap);
                              if (capflag == 0x00000000)
                                    kdDebug(14150) << k_funcinfo << "unknown CAP: " << CapToString(cap) << endl;
                              delete [] cap;

                              //Next comes a big TLV chain of stuff that may or may not exist
                              QPtrList<TLV> tlvlist = tmpbuf.getTLVList();
                              TLV *cur;
                              tlvlist.setAutoDelete(true);

                              for(cur = tlvlist.first();cur;cur = tlvlist.next())
                              {
                                    if (cur->type == 0x0002)
                                    {
                                          //IP address from the perspective of the client
                                          kdDebug(14150) << "ClientIP1: " << cur->data[0] << "."
                                                << cur->data[1] << "." << cur->data[2] << "."
                                                << cur->data[3]  << endl;
                                    }
                                    else if (cur->type == 0x0003)
                                    {
                                          //Secondary IP address from the perspective of the client
                                                kdDebug(14150) << "ClientIP2: " << cur->data[0] << "."
                                                      << cur->data[1] << "." << cur->data[2] << "."
                                                      << cur->data[3] << endl;
                                    }
                                    else if (cur->type == 0x0004) //Verified IP address (from perspective of oscar server)
                                    {
                                          DWORD tmpaddr = 0;
                                          for (int i=0;i<4;i++)
                                          {
                                                tmpaddr = (tmpaddr*0x100) + static_cast<unsigned char>(cur->data[i]);
                                          }
                                          qh = cur->data[0] + '.' + cur->data[1] + '.' + cur->data[2] + '.' + cur->data[3];
                                          kdDebug(14150) << "OscarIPRaw: " <<
                                                cur->data[0] << "." << cur->data[1] << "." <<
                                                cur->data[2] << "." << cur->data[3] << endl;
                                          kdDebug(14150) << "OscarIP: " << qh << endl;
                                    }
                                    else if (cur->type == 0x0005) //Port number
                                    {
                                          remotePort = (cur->data[0] << 8) | cur->data[1];
                                          kdDebug(14150) << k_funcinfo << "remotePort=" << remotePort << endl;
                                    }
                                    //else if (cur->type == 0x000a)
                                    //{
                                    //}
                                    //Error code
                                    else if (cur->type == 0x000b)
                                    {
                                          kdDebug(14150) << k_funcinfo << "ICBM ch 2 error code " <<
                                                ((cur->data[1] << 8) | cur->data[0]) << endl;

                                          emit protocolError(
                                                i18n("Rendezvous with buddy failed. Please check your " \
                                                      "internet connection or try the operation again later. " \
                                                      "Error code %1.\n").arg((cur->data[1] << 8) | cur->data[0]), 0);
                                    }
                                    //Invitation message/ chat description
                                    else if (cur->type == 0x000c)
                                    {
                                          message = cur->data;
                                          kdDebug(14150) << k_funcinfo << "Invited to chat " << cur->data << endl;
                                    }
                                    //Character set
                                    else if (cur->type == 0x000d)
                                    {
                                          kdDebug(14150) << k_funcinfo << "Using character set " << cur->data << endl;
                                    }
                                    //Language
                                    else if (cur->type == 0x000e)
                                    {
                                          kdDebug(14150) << k_funcinfo << "Using language " << cur->data << endl;
                                    }
                                    //File transfer
                                    else if (cur->type == 0x2711)
                                    {
                                          Buffer thebuf(cur->data,cur->length);

                                          thebuf.getWord(); //more than 1 file? (0x0002 for multiple files)
                                          thebuf.getWord(); //number of files
                                          fileSize = thebuf.getDWord(); //total size
                                          char *fname = thebuf.getBlock(cur->length - 2 - 2 - 4 - 4); //file name
                                          thebuf.getDWord(); //DWord of 0x00000000
                                          fileName = fname;
                                          delete [] fname;
                                    } // END File transfer
                                    else
                                          kdDebug(14150) << k_funcinfo << "ICBM, unknown TLV type " << cur->type << endl;

                                    delete [] cur->data;
                              } // END for (tlvlist...)
                        }
                        else
                        {
                              kdDebug(14150) << k_funcinfo << "IM: unknown TLV type " << tlv.type << endl;
                        }

                        // Set the appropriate server socket
                        sockToUse = serverSocket(capflag);

                        if (msgtype == 0x0000) // initiate
                        {
                              kdDebug(14150) << k_funcinfo << "adding " << u.sn << " to pending list." << endl;
                              if(capflag & AIM_CAPS_IMIMAGE) //if it is a direct IM rendezvous
                              {
                                    sockToUse->addPendingConnection(u.sn, cook, 0L, qh, 4443, DirectInfo::Outgoing);
                                    emit gotDirectIMRequest(u.sn);
                              }
                              else // file send
                              {
                                    sockToUse->addPendingConnection(u.sn, cook, 0L, qh, remotePort, DirectInfo::Outgoing);
                                    emit gotFileSendRequest(u.sn, message, fileName, fileSize);
                              }
                        }
                        else if (msgtype == 0x0001) //deny
                        {
                              if(capflag & AIM_CAPS_IMIMAGE)
                                    emit protocolError(i18n("Direct IM request denied by %1").arg(u.sn),0);
                              else
                                    emit protocolError(i18n("Send file request denied by %1").arg(QString(u.sn)),0);
                              sockToUse->removeConnection(u.sn);
                        }
                  } // END if (mIsICQ)
#endif
                  break;
            } // END MSGFORMAT_ADVANCED


            case MSGFORMAT_SERVER: // non-acknowledged, server messages (ICQ ONLY I THINK)
            {
                  parseServerIM(inbuf, u);
                  break;
            }; // END MSGFORMAT_SERVER

            default: // unknown channel
                  kdDebug(14150) << "Error: unknown ICBM channel " << channel << endl;
      } // END switch(channel)
}


Generated by  Doxygen 1.6.0   Back to index