1 /* 2 * SNAC - Messaging services 3 * 4 * Copyright (C) 2001 Barnaby Gray <barnaby@beedesign.co.uk> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include "SNAC-MSG.h" 23 24 #include "sstream_fix.h" 25 26 #include "TLV.h" 27 #include "Contact.h" 28 29 using std::string; 30 using std::ostringstream; 31 32 namespace ICQ2000 { 33 34 // --------------- Message (Family 0x0004) SNACs ----------------- 35 36 const unsigned short MESSAGEFLAG_ALLOWED = 0x00000001; 37 const unsigned short MESSAGEFLAG_MISSEDCALLS = 0x00000002; 38 const unsigned short MESSAGEFLAG_TYPING = 0x00000008; 39 OutputBody(Buffer & b) const40 void MsgAddICBMParameterSNAC::OutputBody(Buffer& b) const 41 { 42 b << (unsigned short)0x0000 // channel 43 << (unsigned int) (MESSAGEFLAG_ALLOWED 44 | MESSAGEFLAG_MISSEDCALLS 45 | (m_typing_notif ? MESSAGEFLAG_TYPING : 0)) 46 // message flags 47 << (unsigned short)0x1f40 // max message snac size 48 << (unsigned short)0x03e7 // max sender warning level 49 << (unsigned short)0x03e7 // max receiver warning level 50 << (unsigned short)0x0000 // min message interval 51 << (unsigned short)0x0000; // unknown 52 } 53 MsgSendSNAC(ICQSubType * icqsubtype,bool ad)54 MsgSendSNAC::MsgSendSNAC(ICQSubType *icqsubtype, bool ad) 55 : m_icqsubtype(icqsubtype), m_advanced(ad) { } 56 setSeqNum(unsigned short seqnum)57 void MsgSendSNAC::setSeqNum(unsigned short seqnum) 58 { 59 m_seqnum = seqnum; 60 } 61 setAdvanced(bool ad)62 void MsgSendSNAC::setAdvanced(bool ad) 63 { 64 m_advanced = ad; 65 } 66 setICBMCookie(const ICBMCookie & c)67 void MsgSendSNAC::setICBMCookie(const ICBMCookie& c) 68 { 69 m_cookie = c; 70 } 71 set_capabilities(const Capabilities & c)72 void MsgSendSNAC::set_capabilities(const Capabilities& c) 73 { 74 m_dest_capabilities = c; 75 } 76 OutputBody(Buffer & b) const77 void MsgSendSNAC::OutputBody(Buffer& b) const 78 { 79 // ICBM Cookie 80 b << m_cookie; 81 82 /* There is no consistency in the protocol here, 83 * Messages are sent on channel 1 84 * Advanced messages are sent on channel 2 85 * Everything else on channel 4 86 */ 87 if (m_advanced) { 88 b << (unsigned short)0x0002; 89 90 UINICQSubType *ust = dynamic_cast<UINICQSubType*>(m_icqsubtype); 91 if (ust == NULL) return; 92 // should fix 93 94 // Destination UIN (screenname) 95 b.PackByteString( Contact::UINtoString(ust->getDestination()) ); 96 97 b << (unsigned short)0x0005; 98 Buffer::marker m1 = b.getAutoSizeShortMarker(); 99 100 b << (unsigned short)0x0000 // status 101 << m_cookie; 102 103 Capabilities c; 104 c.set_capability_flag( Capabilities::ICQServerRelay ); 105 c.Output(b); 106 107 b << (unsigned short)0x000a // TLV 108 << (unsigned short)0x0002 109 << (unsigned short)0x0001; 110 111 b << (unsigned short)0x000f // TLV 112 << (unsigned short)0x0000; 113 114 b << (unsigned short)0x2711; // TLV 115 Buffer::marker m2 = b.getAutoSizeShortMarker(); 116 117 b.setLittleEndian(); 118 119 // -- start of first subsection 120 Buffer::marker m3 = b.getAutoSizeShortMarker(); 121 122 // unknown.. 123 b << (unsigned short)0x0007; // Protocol version 124 125 b << (unsigned int) 0x00000000 // Unknown 126 << (unsigned int) 0x00000000 127 << (unsigned int) 0x00000000 128 << (unsigned int) 0x00000000 129 << (unsigned short)0x0000; 130 131 b << (unsigned int) 0x00000003; // Client features (?) 132 b << (unsigned char) 0x00; // Unknown 133 134 b << m_seqnum; 135 136 b.setAutoSizeMarker(m3); 137 // -- end of first subsection 138 139 // -- start of second subsection 140 Buffer::marker m4 = b.getAutoSizeShortMarker(); 141 b << m_seqnum; 142 143 // unknown 144 b << (unsigned int)0x00000000 145 << (unsigned int)0x00000000 146 << (unsigned int)0x00000000; 147 148 b.setAutoSizeMarker(m4); 149 // -- end of second subsection 150 151 m_icqsubtype->Output(b); 152 153 b.setAutoSizeMarker(m1); 154 b.setAutoSizeMarker(m2); 155 156 b.setBigEndian(); 157 b << (unsigned short)0x0003 // TLV 158 << (unsigned short)0x0000; 159 160 return; 161 } 162 163 // non-advanced 164 165 if (m_icqsubtype->getType() == MSG_Type_Normal) { 166 NormalICQSubType *nst = static_cast<NormalICQSubType*>(m_icqsubtype); 167 168 b << (unsigned short)0x0001; 169 170 // Destination UIN (screenname) 171 b.PackByteString( Contact::UINtoString(nst->getDestination()) ); 172 173 string text = nst->getMessage(); 174 175 /* 176 * Message Block TLV 177 * - contains two TLVs 178 * 0x0501 - don't know what this is 179 * 0x0101 - the message 180 */ 181 b << (unsigned short)0x0002; 182 Buffer::marker m1 = b.getAutoSizeShortMarker(); 183 184 // TLV 0x0501 - unknown 185 b << (unsigned short)0x0501 186 << (unsigned short)0x0001 187 << (unsigned char) 0x01; 188 189 // TLV 0x0101 - flags + the message 190 b << (unsigned short)0x0101; 191 Buffer::marker m2 = b.getAutoSizeShortMarker(); 192 193 // flags - for what? 194 b << (unsigned short)0x0000 195 << (unsigned short)0x0000; 196 197 b.Pack(text); 198 199 b.setAutoSizeMarker(m1); 200 b.setAutoSizeMarker(m2); 201 202 } else if (m_icqsubtype->getType() == MSG_Type_URL 203 || m_icqsubtype->getType() == MSG_Type_AuthReq 204 || m_icqsubtype->getType() == MSG_Type_AuthAcc 205 || m_icqsubtype->getType() == MSG_Type_AuthRej 206 || m_icqsubtype->getType() == MSG_Type_UserAdd) { 207 UINICQSubType *ust = dynamic_cast<UINICQSubType*>(m_icqsubtype); 208 if (ust == NULL) return; 209 210 b << (unsigned short)0x0004; 211 212 // Destination UIN (screenname) 213 b.PackByteString( Contact::UINtoString(ust->getDestination()) ); 214 215 /* 216 * Data Block TLV 217 */ 218 b << (unsigned short)0x0005; 219 Buffer::marker m1 = b.getAutoSizeShortMarker(); 220 221 b.setLittleEndian(); 222 b << (unsigned int)ust->getSource(); 223 ust->Output(b); 224 b.setAutoSizeMarker(m1); 225 226 } 227 228 /* 229 * Another TLV - dunno what it means 230 * - it doesn't seem to matter if I take this out 231 */ 232 b.setBigEndian(); 233 b << (unsigned short)0x0006 234 << (unsigned short)0x0000; 235 236 } 237 MessageSNAC()238 MessageSNAC::MessageSNAC() : m_icqsubtype(NULL) { } 239 MessageSNAC(const std::string & uin)240 MessageSNAC::MessageSNAC(const std::string &uin) 241 { 242 m_icqsubtype = new UserAddICQSubType(uin, "", "", "", false); 243 UINICQSubType *st = dynamic_cast<UINICQSubType*>(m_icqsubtype); 244 if (st != NULL) 245 st->setSource(Contact::StringtoUIN(uin)); 246 } 247 MessageSNAC(const std::string & uin,const std::string & reason)248 MessageSNAC::MessageSNAC(const std::string &uin, const std::string &reason) 249 { 250 m_icqsubtype = new AuthReqICQSubType(uin, "", "", "", false, reason); 251 UINICQSubType *st = dynamic_cast<UINICQSubType*>(m_icqsubtype); 252 if (st != NULL) 253 st->setSource(Contact::StringtoUIN(uin)); 254 } 255 MessageSNAC(const std::string & uin,const std::string & reason,bool granted)256 MessageSNAC::MessageSNAC(const std::string &uin, const std::string &reason, bool granted) 257 { 258 if (granted) 259 m_icqsubtype = new AuthAccICQSubType(); 260 else 261 m_icqsubtype = new AuthRejICQSubType(reason); 262 UINICQSubType *st = dynamic_cast<UINICQSubType*>(m_icqsubtype); 263 if (st != NULL) 264 st->setSource(Contact::StringtoUIN(uin)); 265 } 266 ~MessageSNAC()267 MessageSNAC::~MessageSNAC() { 268 if (m_icqsubtype != NULL) delete m_icqsubtype; 269 } 270 grabICQSubType()271 ICQSubType* MessageSNAC::grabICQSubType() { 272 ICQSubType *ret = m_icqsubtype; 273 m_icqsubtype = NULL; 274 return ret; 275 } 276 ParseBody(Buffer & b)277 void MessageSNAC::ParseBody(Buffer& b) { 278 // ICBM Cookie 279 b >> m_cookie; 280 281 /* 282 * Channel 0x0001 = Normal message 283 * Channel 0x0002 = Advanced messages 284 * Channel 0x0004 = ICQ specific features (URLs, Added to Contact List, SMS, etc.) 285 */ 286 unsigned short channel; 287 b >> channel; 288 if (channel != 0x0001 && channel != 0x0002 && channel != 0x0004) 289 throw ParseException("Message SNAC 0x0004 0x0007 received on unknown channel"); 290 291 /* 292 * the UserInfo block comes next 293 * this is a screenname, then some tlvs 294 */ 295 m_userinfo.Parse(b); 296 297 /* 298 * the Message block comes now 299 * this is one (maybe more TLVs) with the message garbled 300 * up inside 301 */ 302 if (channel == 0x0001) { 303 TLVList tlvlist; 304 tlvlist.Parse(b, TLV_ParseMode_MessageBlock, 40000u); 305 306 // Normal message 307 if (!tlvlist.exists(TLV_MessageData)) 308 throw ParseException("No message data in SNAC"); 309 310 MessageDataTLV *t = static_cast<MessageDataTLV*>(tlvlist[TLV_MessageData]); 311 // coerce this into the NormalICQSubType 312 NormalICQSubType *nst = new NormalICQSubType(false); 313 nst->setAdvanced(false); 314 nst->setMessage( t->getMessage() ); 315 nst->setEncoding( t->getFlag1() ); 316 m_icqsubtype = nst; 317 318 } else if (channel == 0x0002) { 319 TLVList tlvlist; 320 tlvlist.Parse(b, TLV_ParseMode_AdvMsgBlock, 40000u); 321 322 if (!tlvlist.exists(TLV_AdvMsgData)) 323 throw ParseException("No Advanced Message TLV in SNAC 0x0004 0x0007 on channel 2"); 324 325 AdvMsgDataTLV *t = static_cast<AdvMsgDataTLV*>(tlvlist[TLV_AdvMsgData]); 326 m_icqsubtype = t->grabICQSubType(); 327 328 } else if (channel == 0x0004) { 329 TLVList tlvlist; 330 tlvlist.Parse(b, TLV_ParseMode_MessageBlock, 40000u); 331 332 /* ICQ hacked in messages 333 * - SMS message 334 * - URLs 335 * - Added to contactlist 336 * .. 337 */ 338 339 if (!tlvlist.exists(TLV_ICQData)) 340 throw ParseException("No ICQ data TLV in SNAC 0x0004 0x0007 on channel 4"); 341 342 ICQDataTLV *t = static_cast<ICQDataTLV*>(tlvlist[TLV_ICQData]); 343 m_icqsubtype = t->grabICQSubType(); 344 345 } else { 346 347 ostringstream ostr; 348 ostr << "Message SNAC on unsupported channel: 0x" << std::hex << channel; 349 throw ParseException(ostr.str()); 350 351 } 352 353 if (m_icqsubtype != NULL && dynamic_cast<UINICQSubType*>(m_icqsubtype) != NULL) { 354 UINICQSubType *ust = dynamic_cast<UINICQSubType*>(m_icqsubtype); 355 ust->setSource( m_userinfo.getUIN() ); 356 } 357 358 } 359 MessageACKSNAC()360 MessageACKSNAC::MessageACKSNAC() 361 : m_icqsubtype(NULL) { } 362 MessageACKSNAC(ICBMCookie c,UINICQSubType * icq)363 MessageACKSNAC::MessageACKSNAC(ICBMCookie c, UINICQSubType *icq) 364 : m_cookie(c), m_icqsubtype(icq) { } 365 ~MessageACKSNAC()366 MessageACKSNAC::~MessageACKSNAC() { 367 if (m_icqsubtype != NULL) delete m_icqsubtype; 368 } 369 OutputBody(Buffer & b) const370 void MessageACKSNAC::OutputBody(Buffer& b) const { 371 b << m_cookie 372 << (unsigned short)0x0002; 373 374 b.PackByteString( Contact::UINtoString( m_icqsubtype->getSource() ) ); 375 376 b << (unsigned short)0x0003; // unknown 377 378 b.setLittleEndian(); 379 380 // -- start of first subsection 381 Buffer::marker m1 = b.getAutoSizeShortMarker(); 382 383 // unknown.. 384 b << (unsigned short)0x0007; // Protocol version 385 386 b << (unsigned int) 0x00000000 // Unknown 387 << (unsigned int) 0x00000000 388 << (unsigned int) 0x00000000 389 << (unsigned int) 0x00000000 390 << (unsigned short)0x0000; 391 392 b << (unsigned int) 0x00000003; // Client features (?) 393 b << (unsigned char) 0x00; // Unknown 394 395 b << m_icqsubtype->getSeqNum(); 396 397 b.setAutoSizeMarker(m1); 398 // -- end of first subsection 399 400 // -- start of second subsection 401 Buffer::marker m2 = b.getAutoSizeShortMarker(); 402 b << m_icqsubtype->getSeqNum(); 403 404 // unknown 405 b << (unsigned int)0x00000000 406 << (unsigned int)0x00000000 407 << (unsigned int)0x00000000; 408 409 b.setAutoSizeMarker(m2); 410 // -- end of second subsection 411 412 m_icqsubtype->Output(b); 413 } 414 ParseBody(Buffer & b)415 void MessageACKSNAC::ParseBody(Buffer& b) { 416 b >> m_cookie; 417 418 unsigned short channel; 419 b >> channel; 420 421 string sn; 422 unsigned int uin; 423 b.UnpackByteString(sn); 424 uin = Contact::StringtoUIN(sn); 425 426 b.advance(2); // 0x0003 unknown 427 428 unsigned short len; 429 b.setLittleEndian(); 430 431 // -- first section, mostly unknown/useless 432 b >> len; 433 b.advance(len); 434 // ---- 435 436 // -- second section 437 unsigned short seqnum; 438 b >> len; 439 b >> seqnum; 440 b.advance(len - 2); // 12 zeroes usually 441 // ---- 442 443 ICQSubType *t = ICQSubType::ParseICQSubType(b, true, true); 444 if (t != NULL) { 445 m_icqsubtype = dynamic_cast<UINICQSubType*>(t); 446 if (m_icqsubtype != NULL) { 447 m_icqsubtype->setSource(uin); 448 m_icqsubtype->setSeqNum(seqnum); 449 } else { 450 delete t; 451 } 452 453 } 454 455 /* trailing GUID ? */ 456 if (b.remains() > 0) { 457 unsigned int len; 458 b >> len; 459 b.advance(len); 460 } 461 462 } 463 ParseBody(Buffer & b)464 void MessageOfflineUserSNAC::ParseBody(Buffer& b) { 465 /** 466 * The server sends this packet to you if you try sending a 467 * message to a user who is offline. If it was an advanced 468 * message you sent, then it needs to be retried as a 469 * non-advanced message. 470 */ 471 b >> m_cookie 472 >> m_channel; 473 474 unsigned char len; 475 string sn; 476 b >> len; 477 b.Unpack(sn, len); 478 m_uin = Contact::StringtoUIN(sn); 479 } 480 ParseBody(Buffer & b)481 void MessageTypingNotificationSNAC::ParseBody(Buffer& b) { 482 b >> m_cookie 483 >> m_channel; 484 485 unsigned char len; 486 string sn; 487 b >> len; 488 b.Unpack(sn, len); 489 m_uin = Contact::StringtoUIN(sn); 490 b >> m_type; 491 } 492 493 } 494