adding missing includes; trivial fix - comparison with string literal. by
[centerim.git] / libicq2000 / src / SNAC-SRV.cpp
blob0abe49a8be4d71e9a66f8617fb932400fedd51a5
1 /*
2 * SNAC - Server
4 * Copyright (C) 2001 Barnaby Gray <barnaby@beedesign.co.uk>
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.
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.
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
22 #include "SNAC-SRV.h"
24 #include <memory>
25 #include "sstream_fix.h"
27 #include "TLV.h"
28 #include "Xml.h"
30 #include "time_extra.h"
32 using std::string;
33 using std::auto_ptr;
34 using std::istringstream;
36 namespace ICQ2000 {
38 // --------------------- Server (Family 0x0015) SNACs ---------
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) { }
45 void SrvSendSNAC::OutputBody(Buffer& b) const {
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. :-)
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")));
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)));
72 string xmlstr = xmltree.toString(0);
74 // this is a TLV header
75 b << (unsigned short)0x0001;
76 b << (unsigned short)(xmlstr.size()+37);
78 b.setLittleEndian();
79 b << (unsigned short)(xmlstr.size()+35);
80 b << m_senders_UIN;
82 // think this is the message type
83 b << (unsigned short)2000;
85 // think this is a request id of sorts
86 b << (unsigned short)m_requestID; /* low word of the request ID */
88 b.setBigEndian();
90 // SMS send subtype
91 b << (unsigned short)0x8214;
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;
99 b << (unsigned short)0x0000;
100 b.PackUint16StringNull(xmlstr);
103 SrvRequestOfflineSNAC::SrvRequestOfflineSNAC(unsigned int uin)
104 : m_uin(uin) { }
106 void SrvRequestOfflineSNAC::OutputBody(Buffer& b) const {
107 // this is a TLV header
108 b << (unsigned short)0x0001
109 << (unsigned short)0x000a;
111 b.setLittleEndian();
112 b << (unsigned short)0x0008;
113 b << m_uin;
115 // message type
116 b << (unsigned short)60;
117 // a request id
118 b << (unsigned short)m_requestID; /* low word of the request ID */
122 SrvAckOfflineSNAC::SrvAckOfflineSNAC(unsigned int uin)
123 : m_uin(uin) { }
125 void SrvAckOfflineSNAC::OutputBody(Buffer& b) const {
126 // this is a TLV header
127 b << (unsigned short)0x0001
128 << (unsigned short)0x000a;
130 b.setLittleEndian();
131 b << (unsigned short)0x0008;
132 b << m_uin;
134 // message type
135 b << (unsigned short)62;
136 // a request id
137 b << (unsigned short)m_requestID; /* low word of the request ID */
141 SrvRequestSimpleUserInfo::SrvRequestSimpleUserInfo(unsigned int my_uin, unsigned int user_uin)
142 : m_my_uin(my_uin), m_user_uin(user_uin) { }
144 void SrvRequestSimpleUserInfo::OutputBody(Buffer& b) const {
145 b << (unsigned short)0x0001
146 << (unsigned short)0x0010;
148 b.setLittleEndian();
149 b << (unsigned short)0x000e;
150 b << m_my_uin;
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;
159 SrvRequestShortWP::SrvRequestShortWP
160 (unsigned int my_uin, const string& nickname,
161 const string& firstname, const string& lastname)
163 : m_my_uin(my_uin), m_nickname(nickname),
164 m_firstname(firstname), m_lastname(lastname)
168 void SrvRequestShortWP::OutputBody(Buffer& b) const {
169 b << (unsigned short)0x0001;
171 Buffer::marker m1 = b.getAutoSizeShortMarker();
173 b.setLittleEndian();
174 Buffer::marker m2 = b.getAutoSizeShortMarker();
176 b << m_my_uin;
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);
185 b.setAutoSizeMarker(m1);
186 b.setAutoSizeMarker(m2);
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)
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)
207 void SrvRequestFullWP::OutputBody(Buffer& b) const {
208 b << (unsigned short)0x0001;
210 Buffer::marker m1 = b.getAutoSizeShortMarker();
212 b.setLittleEndian();
213 Buffer::marker m2 = b.getAutoSizeShortMarker();
215 b << m_my_uin;
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);
249 SrvRequestKeywordSearch::SrvRequestKeywordSearch(unsigned int my_uin, const string& keyword)
250 : m_my_uin(my_uin), m_keyword(keyword)
253 void SrvRequestKeywordSearch::OutputBody(Buffer& b) const
255 b << (unsigned short)0x0001;
257 Buffer::marker m1 = b.getAutoSizeShortMarker();
259 b.setLittleEndian();
260 Buffer::marker m2 = b.getAutoSizeShortMarker();
262 b << m_my_uin;
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 */
269 Buffer::marker m3 = b.getAutoSizeShortMarker();
270 b.PackUint16StringNull(m_keyword);
271 b.setAutoSizeMarker(m3);
273 b.setAutoSizeMarker(m1);
274 b.setAutoSizeMarker(m2);
277 SrvRequestDetailUserInfo::SrvRequestDetailUserInfo(unsigned int my_uin, unsigned int user_uin)
278 : m_my_uin(my_uin), m_user_uin(user_uin) { }
280 void SrvRequestDetailUserInfo::OutputBody(Buffer& b) const {
281 b << (unsigned short)0x0001
282 << (unsigned short)0x0010;
284 b.setLittleEndian();
285 b << (unsigned short)0x000e;
286 b << m_my_uin;
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;
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) { }
298 void SrvUpdateMainHomeInfo::OutputBody(Buffer& b) const {
299 b << (unsigned short)0x0001;
301 Buffer::marker m1 = b.getAutoSizeShortMarker();
303 b.setLittleEndian();
304 Buffer::marker m2 = b.getAutoSizeShortMarker();
306 b << m_my_uin;
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);
330 SrvUpdateWorkInfo::SrvUpdateWorkInfo(unsigned int my_uin, const Contact::WorkInfo& work_info)
331 : m_my_uin(my_uin), m_work_info(work_info) { }
333 void SrvUpdateWorkInfo::OutputBody(Buffer& b) const {
334 b << (unsigned short)0x0001;
336 Buffer::marker m1 = b.getAutoSizeShortMarker();
338 b.setLittleEndian();
339 Buffer::marker m2 = b.getAutoSizeShortMarker();
341 b << m_my_uin;
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);
362 SrvUpdateHomepageInfo::SrvUpdateHomepageInfo(unsigned int my_uin, const Contact::HomepageInfo& homepage_info)
363 : m_my_uin(my_uin), m_homepage_info(homepage_info) { }
365 void SrvUpdateHomepageInfo::OutputBody(Buffer& b) const {
366 b << (unsigned short)0x0001;
368 Buffer::marker m1 = b.getAutoSizeShortMarker();
370 b.setLittleEndian();
371 Buffer::marker m2 = b.getAutoSizeShortMarker();
373 b << m_my_uin;
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);
392 SrvUpdateAboutInfo::SrvUpdateAboutInfo(unsigned int my_uin, const string& about_info)
393 : m_my_uin(my_uin), m_about_info(about_info) { }
395 void SrvUpdateAboutInfo::OutputBody(Buffer& b) const {
396 b << (unsigned short)0x0001;
398 Buffer::marker m1 = b.getAutoSizeShortMarker();
400 b.setLittleEndian();
401 Buffer::marker m2 = b.getAutoSizeShortMarker();
403 b << m_my_uin;
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);
413 SrvRequestRandomChat::SrvRequestRandomChat(unsigned int my_uin, unsigned short random_group)
414 : m_my_uin(my_uin), m_random_group(random_group) { }
416 void SrvRequestRandomChat::OutputBody(Buffer& b) const {
417 b << (unsigned short)0x0001;
419 Buffer::marker m1 = b.getAutoSizeShortMarker();
421 b.setLittleEndian();
422 Buffer::marker m2 = b.getAutoSizeShortMarker();
424 b << m_my_uin;
426 b << (unsigned short)2000 /* type 9808 */
427 << (unsigned short)m_requestID /* low word of the request ID */
428 << (unsigned short)0x074E; /* subtype */
430 b << (unsigned short)m_random_group;
431 b.setAutoSizeMarker(m1);
432 b.setAutoSizeMarker(m2);
435 SrvSetRandomChatGroup::SrvSetRandomChatGroup(unsigned int my_uin, unsigned short random_group)
436 : m_my_uin(my_uin), m_random_group(random_group) { }
438 void SrvSetRandomChatGroup::OutputBody(Buffer& b) const {
439 int i;
440 b << (unsigned short)0x0001;
442 Buffer::marker m1 = b.getAutoSizeShortMarker();
444 b.setLittleEndian();
445 Buffer::marker m2 = b.getAutoSizeShortMarker();
447 b << m_my_uin;
449 b << (unsigned short)2000 /* type 9808 */
450 << (unsigned short)m_requestID /* low word of the request ID */
451 << (unsigned short)0x0758; /* subtype */
453 b << (unsigned short)m_random_group;
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;
465 b.setAutoSizeMarker(m1);
466 b.setAutoSizeMarker(m2);
469 SrvResponseSNAC::SrvResponseSNAC() : m_icqsubtype(NULL) { }
471 SrvResponseSNAC::~SrvResponseSNAC() {
472 if (m_icqsubtype != NULL) delete m_icqsubtype;
475 void SrvResponseSNAC::ParseBody(Buffer& b) {
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
485 // a TLV header
486 unsigned short type, length;
487 b >> type;
488 b >> length;
490 b.setLittleEndian();
491 // the length again in little endian
492 b >> length;
494 unsigned int uin;
495 b >> uin;
497 /* Command type:
498 * 65 (dec) = An Offline message
499 * 66 (dec) = Offline Messages Finish
500 * 2010 (dec) = ICQ Extended response
501 * others.. ??
503 unsigned short command_type;
504 b >> command_type;
506 unsigned short request_id;
507 b >> request_id;
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");
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;
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;
542 m_time = gmt_mktime(&timetm);
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
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 );
555 void SrvResponseSNAC::ParseICQResponse(Buffer& b) {
557 unsigned short subtype;
558 b >> subtype;
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");
602 void SrvResponseSNAC::ParseInfoChangeAck(Buffer &b, unsigned short subtype) {
603 switch(subtype)
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");
621 b.advance(1); // there's a 0x0a there
623 if (b.beforeEnd())
624 throw ParseException("Extra data at info change acknowledgment (could be an SMS response)");
627 void SrvResponseSNAC::ParseSMSError(Buffer& b) {
628 m_type = SMS_Error;
629 // to do - maybe?
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
637 m_type = SMS_Response;
639 /* Don't know what the next lot of data
640 * means:
641 * 0a 00 01 00 08 00 01
643 unsigned char waste_char;
644 for (int a = 0; a < 7; a++)
645 b >> waste_char;
647 b.setBigEndian();
648 string tag;
649 b >> tag;
651 string xmlstr;
652 b >> xmlstr;
654 string::iterator s = xmlstr.begin();
655 auto_ptr<XmlNode> top(XmlNode::parse(s, xmlstr.end()));
657 if (top.get() == NULL) throw ParseException("Couldn't parse xml data in Server Response SNAC");
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");
663 XmlLeaf *source = sms_response->getLeaf("source");
664 if (source != NULL) m_source = source->getValue();
666 XmlLeaf *deliverable = sms_response->getLeaf("deliverable");
667 m_deliverable = false;
668 m_smtp_deliverable = false;
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;
678 if (m_deliverable) {
679 // -- deliverable = Yes --
681 XmlLeaf *network = sms_response->getLeaf("network");
682 if (network != NULL) m_network = network->getValue();
684 XmlLeaf *message_id = sms_response->getLeaf("message_id");
685 if (message_id != NULL) m_message_id = message_id->getValue();
687 XmlLeaf *messages_left = sms_response->getLeaf("messages_left");
688 if (messages_left != NULL) m_messages_left = messages_left->getValue();
689 // always 0, unsurprisingly
691 } else if (m_smtp_deliverable) {
692 // -- deliverable = SMTP --
694 XmlLeaf *smtp_from = sms_response->getLeaf("from");
695 if (smtp_from != NULL) m_smtp_from = smtp_from->getValue();
697 XmlLeaf *smtp_to = sms_response->getLeaf("to");
698 if (smtp_to != NULL) m_smtp_to = smtp_to->getValue();
700 XmlLeaf *smtp_subject = sms_response->getLeaf("subject");
701 if (smtp_subject != NULL) m_smtp_subject = smtp_subject->getValue();
703 } else {
704 // -- deliverable = No --
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;
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();
725 } // end <error> tag
728 } // end deliverable = No
733 void SrvResponseSNAC::ParseDetailedUserInfo(Buffer& b, unsigned short subtype) {
734 unsigned char wb;
735 b >> wb; // status code ?
737 switch(subtype) {
738 case SrvResponse_MainHomeInfo:
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);
761 // some end marker?
762 unsigned short wi;
763 b >> wi;
765 m_type = RMainHomeInfo;
766 break;
768 case SrvResponse_HomePageInfo:
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;
792 case SrvResponse_EmailInfo:
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;
802 m_type = REmailInfo;
803 break;
805 case SrvResponse_WorkInfo:
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;
823 case SrvResponse_AboutInfo:
824 b.UnpackUint16StringNull(m_about);
825 m_type = RAboutInfo;
826 break;
827 case SrvResponse_InterestInfo:
829 unsigned char n;
830 b >> n;
831 while (n > 0)
833 unsigned short cat;
834 string spec;
835 b >> cat;
836 b.UnpackUint16StringNull(spec);
837 m_personal_interest_info.addInterest(cat, spec);
838 --n;
840 m_type = RInterestInfo;
841 break;
843 case SrvResponse_BackgroundInfo:
845 unsigned char n;
846 b >> n;
847 while (n > 0)
849 unsigned short cat;
850 string s;
851 b >> cat;
852 b.UnpackUint16StringNull(s);
853 m_background_info.addSchool(cat, s);
854 --n;
857 unsigned char junk;
858 b >> junk;
859 m_type = RBackgroundInfo;
860 break;
862 case SrvResponse_Unknown:
864 unsigned short ws;
865 b >> ws;
866 m_type = RUnknown;
867 break;
869 default:
870 throw ParseException("Unknown mode for Detailed user info parsing");
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;
878 if (subtype == SrvResponse_SimpleUI_Done || subtype == SrvResponse_SearchUI_Done) m_last_in_search = true;
879 else m_last_in_search = false;
881 unsigned char wb;
882 b >> wb;
884 * status code
885 * = 0a usually
886 * = 32 on returning no contacts
888 if (wb == 0x32 || wb == 0x14) {
889 m_empty_contact = true;
890 return;
893 m_empty_contact = false;
895 unsigned short ws;
896 b >> ws; // unknown
898 b >> m_uin;
900 b.UnpackUint16StringNull(m_alias);
901 b.UnpackUint16StringNull(m_firstname);
902 b.UnpackUint16StringNull(m_lastname);
903 b.UnpackUint16StringNull(m_email);
905 // Auth required
906 b >> wb;
907 if (wb == 0) m_authreq = true;
908 else m_authreq = false;
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;
928 b >> wb; // unknown
930 if (b.remains() == 3 || b.remains() == 7) {
931 b >> m_sex;
932 b >> m_age;
933 b >> wb; // unknown
936 if (subtype == SrvResponse_SimpleUI_Done || subtype == SrvResponse_SearchUI_Done) {
937 b >> m_more_results;
942 void SrvResponseSNAC::ParseRandomChatFound(Buffer& b) {
943 unsigned char wb;
945 m_empty_contact = false;
946 m_type = RandomChatFound;
948 b >> wb;
949 b >> m_uin;
950 b >> wb;
953 void SrvResponseSNAC::ParseRandomGroupSetAck(Buffer& b) {
954 m_type = RandomGroupSet;