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