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
25 #include "sstream_fix.h"
30 #include "time_extra.h"
34 using std::istringstream
;
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 */
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);
79 b
<< (unsigned short)(xmlstr
.size()+35);
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 */
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
)
106 void SrvRequestOfflineSNAC::OutputBody(Buffer
& b
) const {
107 // this is a TLV header
108 b
<< (unsigned short)0x0001
109 << (unsigned short)0x000a;
112 b
<< (unsigned short)0x0008;
116 b
<< (unsigned short)60;
118 b
<< (unsigned short)m_requestID
; /* low word of the request ID */
122 SrvAckOfflineSNAC::SrvAckOfflineSNAC(unsigned int uin
)
125 void SrvAckOfflineSNAC::OutputBody(Buffer
& b
) const {
126 // this is a TLV header
127 b
<< (unsigned short)0x0001
128 << (unsigned short)0x000a;
131 b
<< (unsigned short)0x0008;
135 b
<< (unsigned short)62;
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;
149 b
<< (unsigned short)0x000e;
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 */
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();
174 Buffer::marker m2
= b
.getAutoSizeShortMarker();
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();
213 Buffer::marker m2
= b
.getAutoSizeShortMarker();
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);
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();
260 Buffer::marker m2
= b
.getAutoSizeShortMarker();
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;
285 b
<< (unsigned short)0x000e;
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 */
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();
304 Buffer::marker m2
= b
.getAutoSizeShortMarker();
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;
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();
339 Buffer::marker m2
= b
.getAutoSizeShortMarker();
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();
371 Buffer::marker m2
= b
.getAutoSizeShortMarker();
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();
401 Buffer::marker m2
= b
.getAutoSizeShortMarker();
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();
422 Buffer::marker m2
= b
.getAutoSizeShortMarker();
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 {
440 b
<< (unsigned short)0x0001;
442 Buffer::marker m1
= b
.getAutoSizeShortMarker();
445 Buffer::marker m2
= b
.getAutoSizeShortMarker();
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;
459 for(i
= 0; i
< 3; i
++) b
<< (unsigned short) 0x0000;
461 for(i
= 0; i
< 3; i
++) b
<< (char) 0x0;
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
486 unsigned short type
, length
;
491 // the length again in little endian
498 * 65 (dec) = An Offline message
499 * 66 (dec) = Offline Messages Finish
500 * 2010 (dec) = ICQ Extended response
503 unsigned short command_type
;
506 unsigned short 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
;
515 } else if (command_type
== 2010) {
518 throw ParseException("Unknown command type for Server Response SNAC");
523 void SrvResponseSNAC::ParseOfflineMessage(Buffer
& b
) {
526 unsigned char month
, day
, hour
, minute
;
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;
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
;
561 case SrvResponse_Error
:
562 ParseSMSError(b
); // fix
564 case SrvResponse_SMS_Done
:
567 case SrvResponse_SimpleUI
:
568 case SrvResponse_SimpleUI_Done
:
569 case SrvResponse_SearchUI
:
570 case SrvResponse_SearchUI_Done
:
571 ParseSimpleUserInfo(b
, subtype
);
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
);
583 case SrvResponse_AckMainHomeInfoChange
:
584 case SrvResponse_AckWorkInfoChange
:
585 case SrvResponse_AckHomepageInfoChange
:
586 case SrvResponse_AckAboutInfoChange
:
587 ParseInfoChangeAck(b
, subtype
);
589 case SrvResponse_RandomChatFound
:
590 ParseRandomChatFound(b
);
592 case SrvResponse_AckRandomGroupSet
:
593 ParseRandomGroupSetAck(b
);
596 throw ParseException("Unknown ICQ subtype for Server response SNAC");
602 void SrvResponseSNAC::ParseInfoChangeAck(Buffer
&b
, unsigned short subtype
) {
605 case SrvResponse_AckMainHomeInfoChange
:
606 m_type
= AckMainHomeInfoChange
;
608 case SrvResponse_AckWorkInfoChange
:
609 m_type
= AckWorkInfoChange
;
611 case SrvResponse_AckHomepageInfoChange
:
612 m_type
= AckHomepageInfoChange
;
614 case SrvResponse_AckAboutInfoChange
:
615 m_type
= AckAboutInfoChange
;
618 throw ParseException("Unknown info change acknowledgment");
621 b
.advance(1); // there's a 0x0a there
624 throw ParseException("Extra data at info change acknowledgment (could be an SMS response)");
627 void SrvResponseSNAC::ParseSMSError(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
637 m_type
= SMS_Response
;
639 /* Don't know what the next lot of data
641 * 0a 00 01 00 08 00 01
643 unsigned char waste_char
;
644 for (int a
= 0; a
< 7; a
++)
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;
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();
704 // -- deliverable = No --
706 // should be an <error> tag
707 XmlBranch
*error
= sms_response
->getBranch("error");
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());
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();
728 } // end deliverable = No
733 void SrvResponseSNAC::ParseDetailedUserInfo(Buffer
& b
, unsigned short subtype
) {
735 b
>> wb
; // status code ?
738 case SrvResponse_MainHomeInfo
:
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
;
755 m_main_home_info
.country
= Country(country
);
756 signed char timezone
;
758 m_main_home_info
.timezone
= Timezone(timezone
);
765 m_type
= RMainHomeInfo
;
768 case SrvResponse_HomePageInfo
:
770 b
>> m_homepage_info
.age
;
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
;
782 m_homepage_info
.lang1
= Language(lang1
);
784 m_homepage_info
.lang2
= Language(lang2
);
786 m_homepage_info
.lang3
= Language(lang3
);
789 m_type
= RHomepageInfo
;
792 case SrvResponse_EmailInfo
:
798 b
.UnpackUint16StringNull(s
);
799 m_email_info
.addEmailAddress(s
);
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
);
819 b
.UnpackUint16StringNull(m_work_info
.company_web
);
823 case SrvResponse_AboutInfo
:
824 b
.UnpackUint16StringNull(m_about
);
827 case SrvResponse_InterestInfo
:
836 b
.UnpackUint16StringNull(spec
);
837 m_personal_interest_info
.addInterest(cat
, spec
);
840 m_type
= RInterestInfo
;
843 case SrvResponse_BackgroundInfo
:
852 b
.UnpackUint16StringNull(s
);
853 m_background_info
.addSchool(cat
, s
);
859 m_type
= RBackgroundInfo
;
862 case SrvResponse_Unknown
:
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;
886 * = 32 on returning no contacts
888 if (wb
== 0x32 || wb
== 0x14) {
889 m_empty_contact
= true;
893 m_empty_contact
= false;
900 b
.UnpackUint16StringNull(m_alias
);
901 b
.UnpackUint16StringNull(m_firstname
);
902 b
.UnpackUint16StringNull(m_lastname
);
903 b
.UnpackUint16StringNull(m_email
);
907 if (wb
== 0) m_authreq
= true;
908 else m_authreq
= false;
915 m_status
= STATUS_OFFLINE
;
918 m_status
= STATUS_ONLINE
;
922 m_status
= STATUS_OFFLINE
;
925 m_status
= STATUS_OFFLINE
;
930 if (b
.remains() == 3 || b
.remains() == 7) {
936 if (subtype
== SrvResponse_SimpleUI_Done
|| subtype
== SrvResponse_SearchUI_Done
) {
942 void SrvResponseSNAC::ParseRandomChatFound(Buffer
& b
) {
945 m_empty_contact
= false;
946 m_type
= RandomChatFound
;
953 void SrvResponseSNAC::ParseRandomGroupSetAck(Buffer
& b
) {
954 m_type
= RandomGroupSet
;