1 /* 2 * SNAC - Server 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-SRV.h" 23 24 #include <memory> 25 #include "sstream_fix.h" 26 27 #include "TLV.h" 28 #include "Xml.h" 29 30 #include "time_extra.h" 31 32 using std::string; 33 using std::auto_ptr; 34 using std::istringstream; 35 36 namespace ICQ2000 { 37 38 // --------------------- Server (Family 0x0015) SNACs --------- 39 SrvSendSNAC(const string & text,const string & destination,unsigned int senders_UIN,const string & senders_name,bool delrpt)40 SrvSendSNAC::SrvSendSNAC(const string& text, const string& destination, 41 unsigned int senders_UIN, const string& senders_name, bool delrpt) 42 : m_text(text), m_destination(destination), m_senders_name(senders_name), 43 m_senders_UIN(senders_UIN), m_delivery_receipt(delrpt) { } 44 OutputBody(Buffer & b) const45 void SrvSendSNAC::OutputBody(Buffer& b) const { 46 47 /* 48 * Sending SMS messages 49 * This is the biggest hodge-podge of a mess you 50 * could imagine in a protocol, a mix of Big and Little Endian, 51 * AIM TLVs and ICQ binary data and add in some XML 52 * to top it all off. :-) 53 */ 54 55 XmlBranch xmltree("icq_sms_message"); 56 xmltree.pushnode(new XmlLeaf("destination",m_destination)); 57 xmltree.pushnode(new XmlLeaf("text",m_text)); 58 xmltree.pushnode(new XmlLeaf("codepage","1252")); 59 xmltree.pushnode(new XmlLeaf("senders_UIN",Contact::UINtoString(m_senders_UIN))); 60 xmltree.pushnode(new XmlLeaf("senders_name",m_senders_name)); 61 xmltree.pushnode(new XmlLeaf("delivery_receipt",(m_delivery_receipt ? "Yes" : "No"))); 62 63 /* Time string, format: Wkd, DD Mnm YYYY HH:MM:SS TMZ */ 64 char timestr[30]; 65 time_t t; 66 struct tm *tm; 67 time(&t); 68 tm = gmtime(&t); 69 strftime(timestr, 30, "%a, %d %b %Y %T %Z", tm); 70 xmltree.pushnode(new XmlLeaf("time",string(timestr))); 71 72 string xmlstr = xmltree.toString(0); 73 74 // this is a TLV header 75 b << (unsigned short)0x0001; 76 b << (unsigned short)(xmlstr.size()+37); 77 78 b.setLittleEndian(); 79 b << (unsigned short)(xmlstr.size()+35); 80 b << m_senders_UIN; 81 82 // think this is the message type 83 b << (unsigned short)2000; 84 85 // think this is a request id of sorts 86 b << (unsigned short)m_requestID; /* low word of the request ID */ 87 88 b.setBigEndian(); 89 90 // SMS send subtype 91 b << (unsigned short)0x8214; 92 93 // not sure about what this means 94 b << (unsigned short)0x0001; 95 b << (unsigned short)0x0016; 96 for(int a = 0; a < 16; a++) 97 b << (unsigned char)0x00; 98 99 b << (unsigned short)0x0000; 100 b.PackUint16StringNull(xmlstr); 101 } 102 SrvRequestOfflineSNAC(unsigned int uin)103 SrvRequestOfflineSNAC::SrvRequestOfflineSNAC(unsigned int uin) 104 : m_uin(uin) { } 105 OutputBody(Buffer & b) const106 void SrvRequestOfflineSNAC::OutputBody(Buffer& b) const { 107 // this is a TLV header 108 b << (unsigned short)0x0001 109 << (unsigned short)0x000a; 110 111 b.setLittleEndian(); 112 b << (unsigned short)0x0008; 113 b << m_uin; 114 115 // message type 116 b << (unsigned short)60; 117 // a request id 118 b << (unsigned short)m_requestID; /* low word of the request ID */ 119 120 } 121 SrvAckOfflineSNAC(unsigned int uin)122 SrvAckOfflineSNAC::SrvAckOfflineSNAC(unsigned int uin) 123 : m_uin(uin) { } 124 OutputBody(Buffer & b) const125 void SrvAckOfflineSNAC::OutputBody(Buffer& b) const { 126 // this is a TLV header 127 b << (unsigned short)0x0001 128 << (unsigned short)0x000a; 129 130 b.setLittleEndian(); 131 b << (unsigned short)0x0008; 132 b << m_uin; 133 134 // message type 135 b << (unsigned short)62; 136 // a request id 137 b << (unsigned short)m_requestID; /* low word of the request ID */ 138 139 } 140 SrvRequestSimpleUserInfo(unsigned int my_uin,unsigned int user_uin)141 SrvRequestSimpleUserInfo::SrvRequestSimpleUserInfo(unsigned int my_uin, unsigned int user_uin) 142 : m_my_uin(my_uin), m_user_uin(user_uin) { } 143 OutputBody(Buffer & b) const144 void SrvRequestSimpleUserInfo::OutputBody(Buffer& b) const { 145 b << (unsigned short)0x0001 146 << (unsigned short)0x0010; 147 148 b.setLittleEndian(); 149 b << (unsigned short)0x000e; 150 b << m_my_uin; 151 152 b << (unsigned short)2000 /* type 9808 */ 153 << (unsigned short)m_requestID /* low word of the request ID */ 154 << (unsigned short)1311 /* subtype (unsigned short)1311 */ 155 << m_user_uin; 156 157 } 158 SrvRequestShortWP(unsigned int my_uin,const string & nickname,const string & firstname,const string & lastname)159 SrvRequestShortWP::SrvRequestShortWP 160 (unsigned int my_uin, const string& nickname, 161 const string& firstname, const string& lastname) 162 163 : m_my_uin(my_uin), m_nickname(nickname), 164 m_firstname(firstname), m_lastname(lastname) 165 { } 166 167 OutputBody(Buffer & b) const168 void SrvRequestShortWP::OutputBody(Buffer& b) const { 169 b << (unsigned short)0x0001; 170 171 Buffer::marker m1 = b.getAutoSizeShortMarker(); 172 173 b.setLittleEndian(); 174 Buffer::marker m2 = b.getAutoSizeShortMarker(); 175 176 b << m_my_uin; 177 178 b << (unsigned short)2000 /* type 9808 */ 179 << (unsigned short)m_requestID /* low word of the request ID */ 180 << (unsigned short)0x0515; /* subtype wp-short-request */ 181 b.PackUint16StringNull(m_firstname); 182 b.PackUint16StringNull(m_lastname); 183 b.PackUint16StringNull(m_nickname); 184 185 b.setAutoSizeMarker(m1); 186 b.setAutoSizeMarker(m2); 187 } 188 189 SrvRequestFullWP(unsigned int my_uin,const string & nickname,const string & firstname,const string & lastname,const string & email,unsigned short min_age,unsigned short max_age,unsigned char sex,unsigned char language,const string & city,const string & state,unsigned short country,const string & company_name,const string & department,const string & position,bool only_online)190 SrvRequestFullWP::SrvRequestFullWP 191 (unsigned int my_uin, const string& nickname, 192 const string& firstname, const string& lastname, 193 const string& email, unsigned short min_age, unsigned short max_age, 194 unsigned char sex, unsigned char language, const string& city, const string& state, 195 unsigned short country, const string& company_name, const string& department, 196 const string& position, bool only_online) 197 198 : m_my_uin(my_uin), m_nickname(nickname), 199 m_firstname(firstname), m_lastname(lastname), 200 m_email(email), m_min_age(min_age), m_max_age(max_age), 201 m_sex(sex), m_language(language), m_city(city), m_state(state), 202 m_company_name(company_name), m_department(department), m_position(position), 203 m_country(country), m_only_online(only_online) 204 205 { } 206 OutputBody(Buffer & b) const207 void SrvRequestFullWP::OutputBody(Buffer& b) const { 208 b << (unsigned short)0x0001; 209 210 Buffer::marker m1 = b.getAutoSizeShortMarker(); 211 212 b.setLittleEndian(); 213 Buffer::marker m2 = b.getAutoSizeShortMarker(); 214 215 b << m_my_uin; 216 217 b << (unsigned short)2000 /* type 9808 */ 218 << (unsigned short)m_requestID /* low word of the request ID */ 219 << (unsigned short)0x0533; /* subtype wp-full-request */ 220 b.PackUint16StringNull(m_firstname); 221 b.PackUint16StringNull(m_lastname); 222 b.PackUint16StringNull(m_nickname); 223 b.PackUint16StringNull(m_email); 224 b << (unsigned short)m_min_age; // minimum age 225 b << (unsigned short)m_max_age; // maximum age 226 b << (unsigned char)m_sex; // sex 227 b << (unsigned char)m_language; // language 228 b.PackUint16StringNull(m_city); // city 229 b.PackUint16StringNull(m_state); // state 230 b << (unsigned short)m_country; // country 231 b.PackUint16StringNull(m_company_name); // company name 232 b.PackUint16StringNull(m_department); // department 233 b.PackUint16StringNull(m_position); // position 234 b << (unsigned char)0x00; // occupation 235 b << (unsigned short)0x0000; // past info category 236 b.PackUint16StringNull(""); // description 237 b << (unsigned short)0x0000; // interests category 238 b.PackUint16StringNull(""); // description 239 b << (unsigned short)0x0000; // affiliation/organization 240 b.PackUint16StringNull(""); // description 241 b << (unsigned short)0x0000; // homepage category 242 b.PackUint16StringNull(""); // description 243 b << (unsigned char)(m_only_online ? 0x01 : 0x00); 244 // only-online flag 245 b.setAutoSizeMarker(m1); 246 b.setAutoSizeMarker(m2); 247 } 248 SrvRequestKeywordSearch(unsigned int my_uin,const string & keyword)249 SrvRequestKeywordSearch::SrvRequestKeywordSearch(unsigned int my_uin, const string& keyword) 250 : m_my_uin(my_uin), m_keyword(keyword) 251 { } 252 OutputBody(Buffer & b) const253 void SrvRequestKeywordSearch::OutputBody(Buffer& b) const 254 { 255 b << (unsigned short)0x0001; 256 257 Buffer::marker m1 = b.getAutoSizeShortMarker(); 258 259 b.setLittleEndian(); 260 Buffer::marker m2 = b.getAutoSizeShortMarker(); 261 262 b << m_my_uin; 263 264 b << (unsigned short)2000 /* type 9808 */ 265 << (unsigned short)m_requestID /* low word of the request ID */ 266 << (unsigned short)0x055F /* subtype keyword-search */ 267 << (unsigned short)0x0226; /* unknown */ 268 269 Buffer::marker m3 = b.getAutoSizeShortMarker(); 270 b.PackUint16StringNull(m_keyword); 271 b.setAutoSizeMarker(m3); 272 273 b.setAutoSizeMarker(m1); 274 b.setAutoSizeMarker(m2); 275 } 276 SrvRequestDetailUserInfo(unsigned int my_uin,unsigned int user_uin)277 SrvRequestDetailUserInfo::SrvRequestDetailUserInfo(unsigned int my_uin, unsigned int user_uin) 278 : m_my_uin(my_uin), m_user_uin(user_uin) { } 279 OutputBody(Buffer & b) const280 void SrvRequestDetailUserInfo::OutputBody(Buffer& b) const { 281 b << (unsigned short)0x0001 282 << (unsigned short)0x0010; 283 284 b.setLittleEndian(); 285 b << (unsigned short)0x000e; 286 b << m_my_uin; 287 288 b << (unsigned short)2000 /* type 9808 */ 289 << (unsigned short)m_requestID /* low word of the request ID */ 290 << (unsigned short)0x04b2 /* subtype (unsigned short)1311 */ 291 << m_user_uin; 292 293 } 294 SrvUpdateMainHomeInfo(unsigned int my_uin,const Contact::MainHomeInfo & main_home_info)295 SrvUpdateMainHomeInfo::SrvUpdateMainHomeInfo(unsigned int my_uin, const Contact::MainHomeInfo& main_home_info) 296 : m_my_uin(my_uin), m_main_home_info(main_home_info) { } 297 OutputBody(Buffer & b) const298 void SrvUpdateMainHomeInfo::OutputBody(Buffer& b) const { 299 b << (unsigned short)0x0001; 300 301 Buffer::marker m1 = b.getAutoSizeShortMarker(); 302 303 b.setLittleEndian(); 304 Buffer::marker m2 = b.getAutoSizeShortMarker(); 305 306 b << m_my_uin; 307 308 b << (unsigned short)2000 /* type 9808 */ 309 << (unsigned short)m_requestID /* low word of the request ID */ 310 << (unsigned short)0x03ea; /* subtype */ 311 b.PackUint16StringNull(m_main_home_info.alias); // alias 312 b.PackUint16StringNull(m_main_home_info.firstname); // first name 313 b.PackUint16StringNull(m_main_home_info.lastname); // last name 314 b.PackUint16StringNull(m_main_home_info.email); // email 315 b.PackUint16StringNull(m_main_home_info.city); // city 316 b.PackUint16StringNull(m_main_home_info.state); // state 317 b.PackUint16StringNull(m_main_home_info.phone); // phone 318 b.PackUint16StringNull(m_main_home_info.fax); // fax 319 b.PackUint16StringNull(m_main_home_info.street); // street 320 b.PackUint16StringNull(m_main_home_info.getMobileNo()); // cellular 321 b.PackUint16StringNull(m_main_home_info.zip); // zip 322 b << m_main_home_info.country; 323 b << m_main_home_info.timezone; 324 unsigned char publish_email = 0; 325 b << publish_email; 326 b.setAutoSizeMarker(m1); 327 b.setAutoSizeMarker(m2); 328 } 329 SrvUpdateWorkInfo(unsigned int my_uin,const Contact::WorkInfo & work_info)330 SrvUpdateWorkInfo::SrvUpdateWorkInfo(unsigned int my_uin, const Contact::WorkInfo& work_info) 331 : m_my_uin(my_uin), m_work_info(work_info) { } 332 OutputBody(Buffer & b) const333 void SrvUpdateWorkInfo::OutputBody(Buffer& b) const { 334 b << (unsigned short)0x0001; 335 336 Buffer::marker m1 = b.getAutoSizeShortMarker(); 337 338 b.setLittleEndian(); 339 Buffer::marker m2 = b.getAutoSizeShortMarker(); 340 341 b << m_my_uin; 342 343 b << (unsigned short)2000 /* type 9808 */ 344 << (unsigned short)m_requestID /* low word of the request ID */ 345 << (unsigned short)0x03f3; /* subtype */ 346 b.PackUint16StringNull(m_work_info.city); // city 347 b.PackUint16StringNull(m_work_info.state); // state 348 b << (unsigned short)0x0000 349 << (unsigned short)0x0000; 350 b.PackUint16StringNull(m_work_info.street); // street 351 b.PackUint16StringNull(m_work_info.zip); // zip 352 b << m_work_info.country; // country-code 353 b.PackUint16StringNull(m_work_info.company_name); // company: name 354 b.PackUint16StringNull(m_work_info.company_dept); // company: department 355 b.PackUint16StringNull(m_work_info.company_position); // company: position 356 b << (unsigned short)0x0000; 357 b.PackUint16StringNull(m_work_info.company_web); // company: homepage 358 b.setAutoSizeMarker(m1); 359 b.setAutoSizeMarker(m2); 360 } 361 SrvUpdateHomepageInfo(unsigned int my_uin,const Contact::HomepageInfo & homepage_info)362 SrvUpdateHomepageInfo::SrvUpdateHomepageInfo(unsigned int my_uin, const Contact::HomepageInfo& homepage_info) 363 : m_my_uin(my_uin), m_homepage_info(homepage_info) { } 364 OutputBody(Buffer & b) const365 void SrvUpdateHomepageInfo::OutputBody(Buffer& b) const { 366 b << (unsigned short)0x0001; 367 368 Buffer::marker m1 = b.getAutoSizeShortMarker(); 369 370 b.setLittleEndian(); 371 Buffer::marker m2 = b.getAutoSizeShortMarker(); 372 373 b << m_my_uin; 374 375 b << (unsigned short)2000 /* type 9808 */ 376 << (unsigned short)m_requestID /* low word of the request ID */ 377 << (unsigned short)0x03fd; /* subtype */ 378 b << (unsigned char)m_homepage_info.age; // age 379 b << (unsigned char)0x00; 380 b << (unsigned char)m_homepage_info.sex; // sex-code 381 b.PackUint16StringNull(m_homepage_info.homepage); 382 b << (unsigned short)m_homepage_info.birth_year; 383 b << (unsigned char)m_homepage_info.birth_month; 384 b << (unsigned char)m_homepage_info.birth_day; 385 b << (unsigned char)m_homepage_info.lang1; 386 b << (unsigned char)m_homepage_info.lang2; 387 b << (unsigned char)m_homepage_info.lang3; 388 b.setAutoSizeMarker(m1); 389 b.setAutoSizeMarker(m2); 390 } 391 SrvUpdateAboutInfo(unsigned int my_uin,const string & about_info)392 SrvUpdateAboutInfo::SrvUpdateAboutInfo(unsigned int my_uin, const string& about_info) 393 : m_my_uin(my_uin), m_about_info(about_info) { } 394 OutputBody(Buffer & b) const395 void SrvUpdateAboutInfo::OutputBody(Buffer& b) const { 396 b << (unsigned short)0x0001; 397 398 Buffer::marker m1 = b.getAutoSizeShortMarker(); 399 400 b.setLittleEndian(); 401 Buffer::marker m2 = b.getAutoSizeShortMarker(); 402 403 b << m_my_uin; 404 405 b << (unsigned short)2000 /* type 9808 */ 406 << (unsigned short)m_requestID /* low word of the request ID */ 407 << (unsigned short)0x0406; /* subtype */ 408 b.PackUint16StringNull(m_about_info); 409 b.setAutoSizeMarker(m1); 410 b.setAutoSizeMarker(m2); 411 } 412 SrvRequestRandomChat(unsigned int my_uin,unsigned short random_group)413 SrvRequestRandomChat::SrvRequestRandomChat(unsigned int my_uin, unsigned short random_group) 414 : m_my_uin(my_uin), m_random_group(random_group) { } 415 OutputBody(Buffer & b) const416 void SrvRequestRandomChat::OutputBody(Buffer& b) const { 417 b << (unsigned short)0x0001; 418 419 Buffer::marker m1 = b.getAutoSizeShortMarker(); 420 421 b.setLittleEndian(); 422 Buffer::marker m2 = b.getAutoSizeShortMarker(); 423 424 b << m_my_uin; 425 426 b << (unsigned short)2000 /* type 9808 */ 427 << (unsigned short)m_requestID /* low word of the request ID */ 428 << (unsigned short)0x074E; /* subtype */ 429 430 b << (unsigned short)m_random_group; 431 b.setAutoSizeMarker(m1); 432 b.setAutoSizeMarker(m2); 433 } 434 SrvSetRandomChatGroup(unsigned int my_uin,unsigned short random_group)435 SrvSetRandomChatGroup::SrvSetRandomChatGroup(unsigned int my_uin, unsigned short random_group) 436 : m_my_uin(my_uin), m_random_group(random_group) { } 437 OutputBody(Buffer & b) const438 void SrvSetRandomChatGroup::OutputBody(Buffer& b) const { 439 int i; 440 b << (unsigned short)0x0001; 441 442 Buffer::marker m1 = b.getAutoSizeShortMarker(); 443 444 b.setLittleEndian(); 445 Buffer::marker m2 = b.getAutoSizeShortMarker(); 446 447 b << m_my_uin; 448 449 b << (unsigned short)2000 /* type 9808 */ 450 << (unsigned short)m_requestID /* low word of the request ID */ 451 << (unsigned short)0x0758; /* subtype */ 452 453 b << (unsigned short)m_random_group; 454 455 b << (unsigned short) 0x0000; 456 b << (unsigned short) 0x0220; 457 for(i = 0; i < 6; i++) b << (unsigned short) 0x0000; 458 b << (char) 0x0; 459 for(i = 0; i < 3; i++) b << (unsigned short) 0x0000; 460 b << (char) 0x50; 461 for(i = 0; i < 3; i++) b << (char) 0x0; 462 b << (char) 0x03; 463 for(i = 0; i < 3; i++) b << (char) 0x0; 464 465 b.setAutoSizeMarker(m1); 466 b.setAutoSizeMarker(m2); 467 } 468 SrvResponseSNAC()469 SrvResponseSNAC::SrvResponseSNAC() : m_icqsubtype(NULL) { } 470 ~SrvResponseSNAC()471 SrvResponseSNAC::~SrvResponseSNAC() { 472 if (m_icqsubtype != NULL) delete m_icqsubtype; 473 } 474 ParseBody(Buffer & b)475 void SrvResponseSNAC::ParseBody(Buffer& b) { 476 477 /* It is worth making the distinction between 478 * sms responses and sms delivery responses 479 * - an sms response is sent on this channel always 480 * after an sms is sent 481 * - an sms delivery response is sent from the mobile 482 * if requested and arrives as SNAC 0x0004 0x0007 483 */ 484 485 // a TLV header 486 unsigned short type, length; 487 b >> type; 488 b >> length; 489 490 b.setLittleEndian(); 491 // the length again in little endian 492 b >> length; 493 494 unsigned int uin; 495 b >> uin; 496 497 /* Command type: 498 * 65 (dec) = An Offline message 499 * 66 (dec) = Offline Messages Finish 500 * 2010 (dec) = ICQ Extended response 501 * others.. ?? 502 */ 503 unsigned short command_type; 504 b >> command_type; 505 506 unsigned short request_id; 507 b >> request_id; 508 509 if (command_type == 65) { 510 ParseOfflineMessage(b); 511 } else if (command_type == 66) { 512 m_type = OfflineMessagesComplete; 513 unsigned char waste_char; 514 b >> waste_char; 515 } else if (command_type == 2010) { 516 ParseICQResponse(b); 517 } else { 518 throw ParseException("Unknown command type for Server Response SNAC"); 519 } 520 521 } 522 ParseOfflineMessage(Buffer & b)523 void SrvResponseSNAC::ParseOfflineMessage(Buffer& b) { 524 b >> m_sender_UIN; 525 unsigned short year; 526 unsigned char month, day, hour, minute; 527 b >> year 528 >> month 529 >> day 530 >> hour 531 >> minute; 532 533 struct tm timetm; 534 timetm.tm_sec = 0; 535 timetm.tm_min = minute; 536 timetm.tm_hour = hour; 537 timetm.tm_mday = day; 538 timetm.tm_mon = month-1; 539 timetm.tm_year = year-1900; 540 timetm.tm_isdst = 0; 541 542 m_time = gmt_mktime(&timetm); 543 544 m_type = OfflineMessage; 545 m_icqsubtype = ICQSubType::ParseICQSubType(b, false, false); 546 /* offline message is non-advanced, and not an ack */ 547 b.advance(2); // unknown 548 549 if (m_icqsubtype != NULL && dynamic_cast<UINICQSubType*>(m_icqsubtype) != NULL) { 550 UINICQSubType *ust = dynamic_cast<UINICQSubType*>(m_icqsubtype); 551 ust->setSource( m_sender_UIN ); 552 } 553 } 554 ParseICQResponse(Buffer & b)555 void SrvResponseSNAC::ParseICQResponse(Buffer& b) { 556 557 unsigned short subtype; 558 b >> subtype; 559 560 switch(subtype) { 561 case SrvResponse_Error: 562 ParseSMSError(b); // fix 563 break; 564 case SrvResponse_SMS_Done: 565 ParseSMSResponse(b); 566 break; 567 case SrvResponse_SimpleUI: 568 case SrvResponse_SimpleUI_Done: 569 case SrvResponse_SearchUI: 570 case SrvResponse_SearchUI_Done: 571 ParseSimpleUserInfo(b, subtype); 572 break; 573 case SrvResponse_MainHomeInfo: 574 case SrvResponse_WorkInfo: 575 case SrvResponse_HomePageInfo: 576 case SrvResponse_AboutInfo: 577 case SrvResponse_EmailInfo: 578 case SrvResponse_InterestInfo: 579 case SrvResponse_BackgroundInfo: 580 case SrvResponse_Unknown: 581 ParseDetailedUserInfo(b, subtype); 582 break; 583 case SrvResponse_AckMainHomeInfoChange: 584 case SrvResponse_AckWorkInfoChange: 585 case SrvResponse_AckHomepageInfoChange: 586 case SrvResponse_AckAboutInfoChange: 587 ParseInfoChangeAck(b, subtype); 588 break; 589 case SrvResponse_RandomChatFound: 590 ParseRandomChatFound(b); 591 break; 592 case SrvResponse_AckRandomGroupSet: 593 ParseRandomGroupSetAck(b); 594 break; 595 default: 596 throw ParseException("Unknown ICQ subtype for Server response SNAC"); 597 } 598 599 600 } 601 ParseInfoChangeAck(Buffer & b,unsigned short subtype)602 void SrvResponseSNAC::ParseInfoChangeAck(Buffer &b, unsigned short subtype) { 603 switch(subtype) 604 { 605 case SrvResponse_AckMainHomeInfoChange: 606 m_type = AckMainHomeInfoChange; 607 break; 608 case SrvResponse_AckWorkInfoChange: 609 m_type = AckWorkInfoChange; 610 break; 611 case SrvResponse_AckHomepageInfoChange: 612 m_type = AckHomepageInfoChange; 613 break; 614 case SrvResponse_AckAboutInfoChange: 615 m_type = AckAboutInfoChange; 616 break; 617 default: 618 throw ParseException("Unknown info change acknowledgment"); 619 } 620 621 b.advance(1); // there's a 0x0a there 622 623 if (b.beforeEnd()) 624 throw ParseException("Extra data at info change acknowledgment (could be an SMS response)"); 625 } 626 ParseSMSError(Buffer & b)627 void SrvResponseSNAC::ParseSMSError(Buffer& b) { 628 m_type = SMS_Error; 629 // to do - maybe? 630 } 631 ParseSMSResponse(Buffer & b)632 void SrvResponseSNAC::ParseSMSResponse(Buffer& b) { 633 /* Not sure what the difference between 100 and 150 is 634 * when successful it sends the erroneous 100 and then 150 635 * otherwise only 150 I think 636 */ 637 m_type = SMS_Response; 638 639 /* Don't know what the next lot of data 640 * means: 641 * 0a 00 01 00 08 00 01 642 */ 643 unsigned char waste_char; 644 for (int a = 0; a < 7; a++) 645 b >> waste_char; 646 647 b.setBigEndian(); 648 string tag; 649 b >> tag; 650 651 string xmlstr; 652 b >> xmlstr; 653 654 string::iterator s = xmlstr.begin(); 655 auto_ptr<XmlNode> top(XmlNode::parse(s, xmlstr.end())); 656 657 if (top.get() == NULL) throw ParseException("Couldn't parse xml data in Server Response SNAC"); 658 659 if (top->getTag() != "sms_response") throw ParseException("No <sms_response> tag found in xml data"); 660 XmlBranch *sms_response = dynamic_cast<XmlBranch*>(top.get()); 661 if (sms_response == NULL) throw ParseException("No tags found in xml data"); 662 663 XmlLeaf *source = sms_response->getLeaf("source"); 664 if (source != NULL) m_source = source->getValue(); 665 666 XmlLeaf *deliverable = sms_response->getLeaf("deliverable"); 667 m_deliverable = false; 668 m_smtp_deliverable = false; 669 670 if (deliverable != NULL) { 671 if (deliverable->getValue() == "Yes") m_deliverable = true; 672 if (deliverable->getValue() == "SMTP") { 673 m_deliverable = false; 674 m_smtp_deliverable = true; 675 } 676 } 677 678 if (m_deliverable) { 679 // -- deliverable = Yes -- 680 681 XmlLeaf *network = sms_response->getLeaf("network"); 682 if (network != NULL) m_network = network->getValue(); 683 684 XmlLeaf *message_id = sms_response->getLeaf("message_id"); 685 if (message_id != NULL) m_message_id = message_id->getValue(); 686 687 XmlLeaf *messages_left = sms_response->getLeaf("messages_left"); 688 if (messages_left != NULL) m_messages_left = messages_left->getValue(); 689 // always 0, unsurprisingly 690 691 } else if (m_smtp_deliverable) { 692 // -- deliverable = SMTP -- 693 694 XmlLeaf *smtp_from = sms_response->getLeaf("from"); 695 if (smtp_from != NULL) m_smtp_from = smtp_from->getValue(); 696 697 XmlLeaf *smtp_to = sms_response->getLeaf("to"); 698 if (smtp_to != NULL) m_smtp_to = smtp_to->getValue(); 699 700 XmlLeaf *smtp_subject = sms_response->getLeaf("subject"); 701 if (smtp_subject != NULL) m_smtp_subject = smtp_subject->getValue(); 702 703 } else { 704 // -- deliverable = No -- 705 706 // should be an <error> tag 707 XmlBranch *error = sms_response->getBranch("error"); 708 if (error != NULL) { 709 // should be an <id> tag 710 XmlLeaf *error_id = error->getLeaf("id"); 711 if (error_id != NULL) { 712 // convert error id to a number 713 istringstream istr(error_id->getValue()); 714 m_error_id = 0; 715 istr >> m_error_id; 716 } 717 718 // should also be a <params> branch 719 XmlBranch *params = error->getBranch("params"); 720 if (params != NULL) { 721 // assume only one <param> tag 722 XmlLeaf *param = params->getLeaf("param"); 723 if (param != NULL) m_error_param = param->getValue(); 724 } 725 } // end <error> tag 726 727 728 } // end deliverable = No 729 730 731 } 732 ParseDetailedUserInfo(Buffer & b,unsigned short subtype)733 void SrvResponseSNAC::ParseDetailedUserInfo(Buffer& b, unsigned short subtype) { 734 unsigned char wb; 735 b >> wb; // status code ? 736 737 switch(subtype) { 738 case SrvResponse_MainHomeInfo: 739 { 740 string s; 741 b.UnpackUint16StringNull(m_main_home_info.alias); // alias 742 b.UnpackUint16StringNull(m_main_home_info.firstname); // first name 743 b.UnpackUint16StringNull(m_main_home_info.lastname); // last name 744 b.UnpackUint16StringNull(m_main_home_info.email); // email 745 b.UnpackUint16StringNull(m_main_home_info.city); // city 746 b.UnpackUint16StringNull(m_main_home_info.state); // state 747 b.UnpackUint16StringNull(m_main_home_info.phone); // phone 748 b.UnpackUint16StringNull(m_main_home_info.fax); // fax 749 b.UnpackUint16StringNull(m_main_home_info.street); // street 750 b.UnpackUint16StringNull(s); // cellular 751 m_main_home_info.setMobileNo(s); 752 b.UnpackUint16StringNull(m_main_home_info.zip); // zip 753 unsigned short country; 754 b >> country; 755 m_main_home_info.country = Country(country); 756 signed char timezone; 757 b >> timezone; 758 m_main_home_info.timezone = Timezone(timezone); 759 b.advance(1); 760 761 // some end marker? 762 unsigned short wi; 763 b >> wi; 764 765 m_type = RMainHomeInfo; 766 break; 767 } 768 case SrvResponse_HomePageInfo: 769 { 770 b >> m_homepage_info.age; 771 unsigned char unk; 772 b >> unk; 773 unsigned char sex; 774 b >> sex; 775 m_homepage_info.sex = Sex(sex); 776 b.UnpackUint16StringNull(m_homepage_info.homepage); 777 b >> m_homepage_info.birth_year; 778 b >> m_homepage_info.birth_month; 779 b >> m_homepage_info.birth_day; 780 unsigned char lang1, lang2, lang3; 781 b >> lang1; 782 m_homepage_info.lang1 = Language(lang1); 783 b >> lang2; 784 m_homepage_info.lang2 = Language(lang2); 785 b >> lang3; 786 m_homepage_info.lang3 = Language(lang3); 787 b >> wb; 788 b >> wb; 789 m_type = RHomepageInfo; 790 break; 791 } 792 case SrvResponse_EmailInfo: 793 { 794 unsigned char n; 795 b >> n; 796 while(n > 0) { 797 string s; 798 b.UnpackUint16StringNull(s); 799 m_email_info.addEmailAddress(s); 800 --n; 801 } 802 m_type = REmailInfo; 803 break; 804 } 805 case SrvResponse_WorkInfo: 806 { 807 b.UnpackUint16StringNull(m_work_info.city); 808 b.UnpackUint16StringNull(m_work_info.state); 809 string s; // these fields are incorrect in the spec 810 b.UnpackUint16StringNull(s); 811 b.UnpackUint16StringNull(s); 812 b.UnpackUint16StringNull(m_work_info.street); 813 b.UnpackUint16StringNull(m_work_info.zip); 814 b >> m_work_info.country; 815 b.UnpackUint16StringNull(m_work_info.company_name); 816 b.UnpackUint16StringNull(m_work_info.company_dept); 817 b.UnpackUint16StringNull(m_work_info.company_position); 818 b.advance(2); 819 b.UnpackUint16StringNull(m_work_info.company_web); 820 m_type = RWorkInfo; 821 break; 822 } 823 case SrvResponse_AboutInfo: 824 b.UnpackUint16StringNull(m_about); 825 m_type = RAboutInfo; 826 break; 827 case SrvResponse_InterestInfo: 828 { 829 unsigned char n; 830 b >> n; 831 while (n > 0) 832 { 833 unsigned short cat; 834 string spec; 835 b >> cat; 836 b.UnpackUint16StringNull(spec); 837 m_personal_interest_info.addInterest(cat, spec); 838 --n; 839 } 840 m_type = RInterestInfo; 841 break; 842 } 843 case SrvResponse_BackgroundInfo: 844 { 845 unsigned char n; 846 b >> n; 847 while (n > 0) 848 { 849 unsigned short cat; 850 string s; 851 b >> cat; 852 b.UnpackUint16StringNull(s); 853 m_background_info.addSchool(cat, s); 854 --n; 855 } 856 857 unsigned char junk; 858 b >> junk; 859 m_type = RBackgroundInfo; 860 break; 861 } 862 case SrvResponse_Unknown: 863 { 864 unsigned short ws; 865 b >> ws; 866 m_type = RUnknown; 867 break; 868 } 869 default: 870 throw ParseException("Unknown mode for Detailed user info parsing"); 871 } 872 } 873 ParseSimpleUserInfo(Buffer & b,unsigned short subtype)874 void SrvResponseSNAC::ParseSimpleUserInfo(Buffer& b, unsigned short subtype) { 875 if (subtype == SrvResponse_SimpleUI || subtype == SrvResponse_SimpleUI_Done) m_type = SimpleUserInfo; 876 if (subtype == SrvResponse_SearchUI || subtype == SrvResponse_SearchUI_Done) m_type = SearchSimpleUserInfo; 877 878 if (subtype == SrvResponse_SimpleUI_Done || subtype == SrvResponse_SearchUI_Done) m_last_in_search = true; 879 else m_last_in_search = false; 880 881 unsigned char wb; 882 b >> wb; 883 /* 884 * status code 885 * = 0a usually 886 * = 32 on returning no contacts 887 */ 888 if (wb == 0x32 || wb == 0x14) { 889 m_empty_contact = true; 890 return; 891 } 892 893 m_empty_contact = false; 894 895 unsigned short ws; 896 b >> ws; // unknown 897 898 b >> m_uin; 899 900 b.UnpackUint16StringNull(m_alias); 901 b.UnpackUint16StringNull(m_firstname); 902 b.UnpackUint16StringNull(m_lastname); 903 b.UnpackUint16StringNull(m_email); 904 905 // Auth required 906 b >> wb; 907 if (wb == 0) m_authreq = true; 908 else m_authreq = false; 909 910 // Status 911 unsigned char st; 912 b >> st; 913 switch(st) { 914 case 0: 915 m_status = STATUS_OFFLINE; 916 break; 917 case 1: 918 m_status = STATUS_ONLINE; 919 break; 920 case 2: 921 // status disabled 922 m_status = STATUS_OFFLINE; 923 break; 924 default: 925 m_status = STATUS_OFFLINE; 926 } 927 928 b >> wb; // unknown 929 930 if (b.remains() == 3 || b.remains() == 7) { 931 b >> m_sex; 932 b >> m_age; 933 b >> wb; // unknown 934 } 935 936 if (subtype == SrvResponse_SimpleUI_Done || subtype == SrvResponse_SearchUI_Done) { 937 b >> m_more_results; 938 } 939 940 } 941 ParseRandomChatFound(Buffer & b)942 void SrvResponseSNAC::ParseRandomChatFound(Buffer& b) { 943 unsigned char wb; 944 945 m_empty_contact = false; 946 m_type = RandomChatFound; 947 948 b >> wb; 949 b >> m_uin; 950 b >> wb; 951 } 952 ParseRandomGroupSetAck(Buffer & b)953 void SrvResponseSNAC::ParseRandomGroupSetAck(Buffer& b) { 954 m_type = RandomGroupSet; 955 } 956 957 } 958