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