1 /*
2  * Handles incoming and creates outgoing SNAC packets
3  * for the family 19 (roster) commands.
4  *
5  * climm Copyright (C) © 2001-2007 Rüdiger Kuhlmann
6  *
7  * climm is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; version 2 dated June, 1991.
10  *
11  * climm is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14  * License for more details.
15  *
16  * In addition, as a special exception permission is granted to link the
17  * code of this release of climm with the OpenSSL project's "OpenSSL"
18  * library, and distribute the linked executables.  You must obey the GNU
19  * General Public License in all respects for all of the code used other
20  * than "OpenSSL".  If you modify this file, you may extend this exception
21  * to your version of the file, but you are not obligated to do so.  If you
22  * do not wish to do so, delete this exception statement from your version
23  * of this file.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this package; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
28  * 02111-1307, USA.
29  *
30  * As a special exemption, you may link your binary against OpenSSL,
31  * provided your operating system distribution doesn't ship libgnutls.
32  *
33  * $Id: oscar_roster.c 2831 2009-08-20 21:48:15Z kuhlmann $
34  */
35 
36 #include "climm.h"
37 #include <assert.h>
38 #include "oscar_base.h"
39 #include "oscar_tlv.h"
40 #include "oscar_snac.h"
41 #include "oscar_service.h"
42 #include "oscar_contact.h"
43 #include "oscar_roster.h"
44 #include "oscar_oldicq.h"
45 #include "packet.h"
46 #include "contact.h"
47 #include "connection.h"
48 #include "im_icq8.h"
49 #include "conv.h"
50 #include "file_util.h"
51 #include "util_ui.h"
52 #include "im_response.h"
53 
54 #define TLV_REQAUTH    102
55 #define TLV_GROUPITEMS 200
56 #define TLV_UNKNIDLE   201
57 #define TLV_PRIVACY    202
58 #define TLV_VISIBILITY 203
59 #define TLV_ALLOWIDLE  204
60 #define TLV_ICQTIC     205
61 #define TLV_IMPORT     212
62 #define TLV_ICON       213
63 #define TLV_NICK       305
64 #define TLV_LOCALMAIL  311
65 #define TLV_LOCALSMS   314
66 #define TLV_LOCALCOMM  316
67 #define TLV_LOCALACT   317
68 #define TLV_LOCALSOUND 318
69 #define TLV_LASTUPD    325
70 
OscarRosterC(void)71 Roster *OscarRosterC (void)
72 {
73     return calloc (sizeof (Roster), 1);
74 }
75 
OscarRosterEntryD(RosterEntry * entry)76 static void OscarRosterEntryD (RosterEntry *entry)
77 {
78     RosterEntry *next;
79 
80     while (entry)
81     {
82         s_free (entry->name);
83         s_free (entry->nick);
84         TLVD (entry->tlv);
85         next = entry->next;
86         free (entry);
87         entry = next;
88     }
89 }
90 
OscarRosterD(Roster * roster)91 void OscarRosterD (Roster *roster)
92 {
93     OscarRosterEntryD (roster->generic);
94     OscarRosterEntryD (roster->groups);
95     OscarRosterEntryD (roster->normal);
96     OscarRosterEntryD (roster->visible);
97     OscarRosterEntryD (roster->invisible);
98     OscarRosterEntryD (roster->ignore);
99     s_free (roster->ICQTIC);
100     s_free (roster->delname);
101     free (roster);
102 }
103 
104 /*
105  * CLI_REQLISTS - SNAC(13,2)
106  */
107 
108 /* implemented as macro */
109 
110 /*
111  * SRV_REPLYLISTS - SNAC(13,3)
112  */
JUMP_SNAC_F(SnacSrvReplylists)113 JUMP_SNAC_F(SnacSrvReplylists)
114 {
115     Server *serv = event->conn->serv;
116 
117     if (serv->flags & CONN_WIZARD)
118     {
119         IMRoster (serv, IMROSTER_IMPORT);
120         if (serv->flags & CONN_INITWP)
121         {
122             Contact *cont = ContactScreen (serv, serv->screen);
123             CONTACT_GENERAL (cont);
124             CONTACT_MORE (cont);
125             SnacCliMetasetabout (serv, "climm");
126             SnacCliMetasetgeneral (serv, cont);
127             SnacCliMetasetmore (serv, cont);
128         }
129     }
130     else
131         IMRoster (serv, IMROSTER_DIFF);
132 }
133 
134 /*
135  * CLI_REQROSTER - SNAC(13,4)
136  */
137 
138 /* implemented as macro */
139 
140 /*
141  * CLI_CHECKROSTER - SNAC(13,5)
142  */
SnacCliCheckroster(Server * serv)143 UDWORD SnacCliCheckroster (Server *serv)
144 {
145     ContactGroup *cg;
146     Packet *pak;
147     UDWORD ref;
148     int i;
149 
150     cg = serv->contacts;
151     pak = SnacC (serv, 19, 5, 0, 0);
152     for (i = 0; (/*cont =*/ ContactIndex (cg, i)); )
153         i++;
154 
155     PacketWriteB4 (pak, 0);  /* last modification of server side contact list */
156     PacketWriteB2 (pak, 0);  /* # of entries */
157     ref = pak->ref;
158     SnacSend (serv, pak);
159     return ref;
160 }
161 
162 /*
163  * SRV_REPLYROSTER - SNAC(13,6)
164  */
JUMP_SNAC_F(SnacSrvReplyroster)165 JUMP_SNAC_F(SnacSrvReplyroster)
166 {
167     Server *serv;
168     Packet *pak;
169     Event *event2;
170     Roster *roster;
171     RosterEntry **rref;
172     RosterEntry *re;
173     int i, k, l;
174     int cnt_sbl_add, cnt_sbl_chn, cnt_sbl_del;
175     int cnt_loc_add, cnt_loc_chn, cnt_loc_del;
176     strc_t cname;
177     UWORD count, j, TLVlen;
178     time_t stmp;
179 
180     if (!event)
181         return;
182 
183     serv = event->conn->serv;
184     if (!serv)
185         return;
186 
187     pak = event->pak;
188 
189     if (!pak)
190         return;
191 
192     event2 = QueueDequeue2 (serv->conn, QUEUE_REQUEST_ROSTER, 0, 0);
193     if (!event2 || !event2->callback)
194     {
195         DebugH (DEB_PROTOCOL, "Unrequested roster packet received.\n");
196         return;
197     }
198 
199     roster = event2->data;
200     if (!roster)
201     {
202         roster = OscarRosterC ();
203         event2->data = roster;
204     }
205 
206     PacketRead1 (pak);
207 
208     count = PacketReadB2 (pak);          /* COUNT */
209     cnt_sbl_add = cnt_sbl_chn = cnt_sbl_del = 0;
210     cnt_loc_add = cnt_loc_chn = cnt_loc_del = 0;
211     for (i = k = l = 0; i < count; i++)
212     {
213         re = calloc (sizeof (RosterEntry), 1);
214 
215         cname  = PacketReadB2Str (pak, NULL);   /* GROUP NAME */
216         re->tag  = PacketReadB2 (pak);     /* TAG  */
217         re->id   = PacketReadB2 (pak);     /* ID   */
218         re->type = PacketReadB2 (pak);     /* TYPE */
219         TLVlen = PacketReadB2 (pak);     /* TLV length */
220         re->tlv  = TLVRead (pak, TLVlen, -1);
221 
222         re->name = strdup (ConvFromServ (cname));
223 
224         j = TLVGet (re->tlv, TLV_NICK);
225         assert (j < 200 || j == (UWORD)-1);
226         if (j != (UWORD)-1 && re->tlv[j].str.len)
227             re->nick = strdup (ConvFromServ (&re->tlv[j].str));
228         else
229             re->nick = NULL;
230 
231         rref = &roster->generic;
232         switch (re->type)
233         {
234             case roster_normal:
235                 /* TLV_REQAUTH */
236                 /* TLV_NICK */
237                 /* TLV_LOCALMAIL */
238                 /* TLV_LOCALSMS */
239                 /* TLV_LOCALCOMM */
240                 /* TLV_LOCALACT */
241                 /* TLV_LOCALSOUND */
242                 rref = &roster->normal;
243                 if (TLVGet (re->tlv, TLV_REQAUTH) != (UWORD)-1)
244                     re->reqauth = 1;
245                 break;
246             case roster_group:
247                 /* TLV_GROUPITEMS */
248                 if (re->tag || re->id)
249                     rref = &roster->groups;
250                 break;
251             case roster_visible:
252                 rref = &roster->visible;
253                 break;
254             case roster_invisible:
255                 rref = &roster->invisible;
256                 break;
257             case roster_ignore:
258                 rref = &roster->ignore;
259                 break;
260             case roster_lastupd: /* LastUpdateDate */
261                 /* TLV_LASTUPD */
262                 break;
263             case roster_wierd17: /* wierd */
264             case roster_icon: /* buddy icon */
265                 /* TLV_ICON */
266                 break;
267             case roster_importt: /* ImportTime */
268                 j = TLVGet (re->tlv, TLV_IMPORT);
269                 if (j != (UWORD)-1 && re->tlv[j].str.len == 4)
270                     roster->import = re->tlv[j].nr;
271                 else
272                     rl_printf ("#Bogus ImportTime item: %d: %s %d %d.\n", re->type, re->name, re->tag, re->id);
273                 break;
274             case roster_icqtic:
275                 j = TLVGet (re->tlv, TLV_ICQTIC);
276                 if (j != (UWORD)-1)
277                     s_repl (&roster->ICQTIC, re->tlv[j].str.txt);
278                 break;
279             case roster_visibility:
280                 serv->oscar_privacy_tag = re->id;
281                 j = TLVGet (re->tlv, TLV_PRIVACY);
282                 if (j != (UWORD)-1)
283                 {
284                     serv->oscar_privacy_value = *re->tlv[j].str.txt;
285                     if (*re->tlv[j].str.txt != 3 && *re->tlv[j].str.txt != 4)
286                     {
287                         rl_printf ("# privacy mode: (%d)\n", *re->tlv[j].str.txt);
288                         if (*re->tlv[j].str.txt == 1)
289                             rl_printf ("#     always visible to all users\n");
290                         else if (*re->tlv[j].str.txt == 2)
291                             rl_printf ("#     never visible to anyone\n");
292                         else if (*re->tlv[j].str.txt == 3)
293                             rl_printf ("#     only visible to always visible contacts\n");
294                         else if (*re->tlv[j].str.txt == 4)
295                             rl_printf ("#     always visible except to invisible contacts\n");
296                         else if (*re->tlv[j].str.txt == 5)
297                             rl_printf ("#     always visible to all contacts\n");
298                         else
299                             rl_printf ("#     unknown/invalid privacy mode\n");
300                         rl_printf ("# change with 'contact security <mode>' (to 3 or 4).\n");
301                     }
302                 }
303                 break;
304 
305             case roster_presence:
306             case roster_noncont:
307                 /* TLV_UNKNIDLE   */
308                 /* TLV_PRIVACY    */
309                 /* TLV_VISIBILITY */
310                 /* TLV_ALLOWIDLE  */
311             case roster_wierd25:
312             case roster_wierd27:
313             case roster_wierd29:
314             case roster_wierd32:
315                 break;
316             default:
317                 rl_printf ("#Unknown type %d: %s %d %d.\n", re->type, re->name, re->tag, re->id);
318         }
319 
320         re->next = *rref;
321         *rref = re;
322     }
323     stmp = PacketReadB4 (pak);
324     if (stmp)
325     {
326 #if 0
327         if (!roster->import)
328         {
329             time_t now = time (NULL);
330             UDWORD da = now;
331             SnacCliRosterentryadd (serv, "ImportTime", 0, 1, roster_importt, TLV_IMPORT, &da, 4);
332         }
333         if (!roster->ICQTIC)
334             SnacCliRosterentryadd (serv, "ICQTIC", 0, 2, roster_icqtic, TLV_ICQTIC, "3608,0,0,0,60,null", 18);
335         if (!serv->oscar_privacy_tag)
336         {
337             serv->oscar_privacy_tag = rand () % 0x8000;
338             SnacCliRosterentryadd (serv, "", 0, serv->oscar_privacy_tag, roster_visibility, TLV_PRIVACY, "\x03", 1);
339             serv->oscar_privacy_value = 3;
340         }
341 #endif
342         if (~serv->conn->connect & CONNECT_OK)
343             CliFinishLogin (serv);
344 
345         SnacCliRosterack (serv);
346         event2->callback (event2);
347     }
348     else
349         QueueEnqueue (event2);
350 }
351 
352 /*
353  * CLI_ROSTERACK - SNAC(13,7)
354  */
355 
356 /* implemented as macro */
357 
358 /*
359  * CLI_ADDBUDDY - SNAC(13,8)
360  */
361 
SnacCliRosterbulkdata(Packet * pak,const char * name,UWORD tag,UWORD id,UWORD type)362 static void SnacCliRosterbulkdata (Packet *pak, const char *name, UWORD tag, UWORD id, UWORD type)
363 {
364     PacketWriteStrB     (pak, name);
365     PacketWriteB2       (pak, tag);
366     PacketWriteB2       (pak, id);
367     PacketWriteB2       (pak, type);
368     PacketWriteBLen     (pak);
369 }
370 
SnacCliRosterbulkone(Server * serv,ContactGroup * cg,Contact * cont,Packet * pak,UWORD type,UWORD subtype)371 static void SnacCliRosterbulkone (Server *serv, ContactGroup *cg, Contact *cont, Packet *pak, UWORD type, UWORD subtype)
372 {
373     UWORD tag = 0;
374     ContactIDs *ids;
375 
376     if (type == roster_normal && (ids = ContactIDHas (cont, roster_normal)) && ids->issbl)
377         tag = ids->tag;
378     else if (type == roster_group || type == roster_normal)
379         tag = ContactGroupID (cg);
380 
381     SnacCliRosterbulkdata (pak, type == roster_group ? cg->name : cont->screen, tag,
382                                 type == roster_group ? 0 : ContactIDGet (cont, type), type);
383     if (type == roster_normal && subtype != 10)
384     {
385         PacketWriteTLVStr   (pak, TLV_NICK, cont->nick);
386         if (ContactPrefVal (cont, CO_ASK_SBL))
387         {
388             PacketWriteTLV     (pak, TLV_REQAUTH);
389             PacketWriteTLVDone (pak);
390         }
391     }
392     else if (type == roster_group && subtype == 9)
393     {
394         Contact *cont;
395         int i;
396         PacketWriteTLV      (pak, TLV_GROUPITEMS);
397         for (i = 0; (cont = ContactIndex (cg, i)); i++)
398             if (cont->group == cg)
399                 PacketWriteB2   (pak, ContactIDGet (cont, roster_normal));
400         PacketWriteTLVDone  (pak);
401     }
402     PacketWriteBLenDone (pak);
403     QueueEnqueueData (serv->conn, QUEUE_CHANGE_ROSTER, pak->ref, 0x7fffffffL, NULL, cont, NULL, NULL);
404 }
405 
SnacCliRosterbulkadd(Server * serv,ContactGroup * cs)406 void SnacCliRosterbulkadd (Server *serv, ContactGroup *cs)
407 {
408     Packet *pak;
409     Contact *cont;
410     ContactGroup *cg;
411     int i;
412 
413     for (i = 0; (cont = ContactIndex (cs, i)); i++)
414         if (cont->group && cont->group->serv && !ContactGroupPrefVal (cont->group, CO_ISSBL))
415             SnacCliRosteraddgroup (serv, cont->group, 3);
416 
417     SnacCliAddstart (serv);
418     pak = SnacC (serv, 19, 8, 0, 0);
419 
420     for (i = 0; (cont = ContactIndex (cs, i)); i++)
421     {
422         if (!(cg = cont->group))
423             continue;
424 
425         if (i && !(i % 64))
426         {
427             SnacSend (serv, pak);
428             pak = SnacC (serv, 19, 8, 0, 0);
429         }
430 
431         SnacCliRosterbulkone (serv, cg, cont, pak, roster_normal, 8);
432 
433         if (ContactPrefVal (cont, CO_HIDEFROM))
434         {
435             i++;
436             SnacCliRosterbulkone (serv, NULL, cont, pak, roster_invisible, 8);
437         }
438         if (ContactPrefVal (cont, CO_INTIMATE))
439         {
440             i++;
441             SnacCliRosterbulkone (serv, NULL, cont, pak, roster_visible, 8);
442         }
443         if (ContactPrefVal (cont, CO_IGNORE))
444         {
445             i++;
446             SnacCliRosterbulkone (serv, NULL, cont, pak, roster_ignore, 8);
447         }
448     }
449     SnacSend (serv, pak);
450     SnacCliAddend (serv);
451 }
452 
453 /*
454  * CLI_ADDBUDDY - SNAC(13,8)
455  */
SnacCliRosterentryadd(Server * serv,const char * name,UWORD tag,UWORD id,UWORD type,UWORD tlv,void * data,UWORD len)456 void SnacCliRosterentryadd (Server *serv, const char *name, UWORD tag, UWORD id, UWORD type, UWORD tlv, void *data, UWORD len)
457 {
458     Packet *pak;
459 
460     SnacCliAddstart (serv);
461     pak = SnacC (serv, 19, 8, 0, 0);
462     SnacCliRosterbulkdata (pak, name, tag, id, type);
463     if (tlv)
464         PacketWriteTLVData (pak, tlv, data, len);
465     PacketWriteBLenDone (pak);
466     SnacSend (serv, pak);
467     SnacCliAddend (serv);
468 }
469 
SnacCliRosteraddgroup(Server * serv,ContactGroup * cg,int mode)470 void SnacCliRosteraddgroup (Server *serv, ContactGroup *cg, int mode)
471 {
472     Packet *pak;
473     assert (cg);
474 
475     if (mode & 1)
476         SnacCliAddstart (serv);
477     pak = SnacC (serv, 19, 8, 0, 0);
478     SnacCliRosterbulkone (serv, cg, NULL, pak, roster_group, 8);
479     SnacSend (serv, pak);
480     OptSetVal (&cg->copts, CO_ISSBL, 1);
481     if (mode & 2)
482         SnacCliAddend (serv);
483 }
484 
SnacCliRosteraddcontact(Server * serv,Contact * cont,int mode)485 void SnacCliRosteraddcontact (Server *serv, Contact *cont, int mode)
486 {
487     Packet *pak;
488     assert (cont);
489 
490     if (mode & 1)
491         SnacCliAddstart (serv);
492     if (!ContactGroupPrefVal (cont->group, CO_ISSBL))
493         SnacCliRosteraddgroup (serv, cont->group, 0);
494     pak = SnacC (serv, 19, 8, 0, 0);
495     OptSetVal (&cont->copts, CO_ASK_SBL, 1);
496     SnacCliRosterbulkone (serv, cont->group, cont, pak, roster_normal, 8);
497     if (ContactPrefVal (cont, CO_HIDEFROM))
498         SnacCliRosterbulkone (serv, NULL, cont, pak, roster_invisible, 8);
499     if (ContactPrefVal (cont, CO_INTIMATE))
500         SnacCliRosterbulkone (serv, NULL, cont, pak, roster_visible, 8);
501     if (ContactPrefVal (cont, CO_IGNORE))
502         SnacCliRosterbulkone (serv, NULL, cont, pak, roster_ignore, 8);
503     SnacSend (serv, pak);
504     if (mode & 2)
505         SnacCliAddend (serv);
506 }
507 
508 /*
509  * CLI_ROSTERUPDATE - SNAC(13,9)
510  */
SnacCliRosterupdategroup(Server * serv,ContactGroup * cg,int mode)511 void SnacCliRosterupdategroup (Server *serv, ContactGroup *cg, int mode)
512 {
513     Packet *pak;
514     assert (cg);
515 
516     if (mode & 1)
517         SnacCliAddstart (serv);
518     pak = SnacC (serv, 19, 9, 0, 0);
519     SnacCliRosterbulkone (serv, cg, NULL, pak, roster_group, 9);
520     SnacSend (serv, pak);
521     if (mode & 2)
522         SnacCliAddend (serv);
523 }
524 
SnacCliRosterupdatecontact(Server * serv,Contact * cont,int mode)525 void SnacCliRosterupdatecontact (Server *serv, Contact *cont, int mode)
526 {
527     Packet *pak;
528     assert (cont);
529 
530     if (mode & 1)
531         SnacCliAddstart (serv);
532     if (!ContactGroupPrefVal (cont->group, CO_ISSBL))
533         SnacCliRosteraddgroup (serv, cont->group, 0);
534     pak = SnacC (serv, 19, 9, 0, 0);
535     SnacCliRosterbulkone (serv, cont->group, cont, pak, roster_normal, 9);
536     if (ContactPrefVal (cont, CO_HIDEFROM))
537         SnacCliRosterbulkone (serv, NULL, cont, pak, roster_invisible, 9);
538     if (ContactPrefVal (cont, CO_INTIMATE))
539         SnacCliRosterbulkone (serv, NULL, cont, pak, roster_visible, 9);
540     if (ContactPrefVal (cont, CO_IGNORE))
541         SnacCliRosterbulkone (serv, NULL, cont, pak, roster_ignore, 9);
542     SnacSend (serv, pak);
543     if (mode & 2)
544         SnacCliAddend (serv);
545 }
546 
SnacCliRostermovecontact(Server * serv,Contact * cont,ContactGroup * cg,int mode)547 void SnacCliRostermovecontact (Server *serv, Contact *cont, ContactGroup *cg, int mode)
548 {
549     Packet *pakd, *paka;
550     ContactIDs *ids;
551     char is, want;
552     is = ContactPrefVal (cont, CO_ISSBL);
553     want = ContactPrefVal (cont, CO_WANTSBL);
554 
555     if (!is && !want && mode == 3)
556         return;
557 
558     if (mode & 1)
559         SnacCliAddstart (serv);
560 
561     if (!ContactGroupPrefVal (cg, CO_ISSBL))
562         SnacCliRosteraddgroup (serv, cg, 0);
563 
564     pakd = SnacC (serv, 19, 10, 0, 0);
565     paka = SnacC (serv, 19, 8, 0, 0);
566 
567     if (cont->ids && (ids = ContactIDHas (cont, roster_normal)) && ids->issbl)
568         SnacCliRosterbulkone (serv, cont->group, cont, pakd, roster_normal, 10);
569     cont->group = cg;
570     if (want)
571         SnacCliRosterbulkone (serv, cont->group, cont, paka, roster_normal, 8);
572 
573     SnacSend (serv, pakd);
574     SnacSend (serv, paka);
575 
576     if (mode & 2)
577         SnacCliAddend (serv);
578 }
579 
SnacCliRosterbulkmove(Server * serv,ContactGroup * cg,int mode)580 void SnacCliRosterbulkmove (Server *serv, ContactGroup *cg, int mode)
581 {
582     Packet *pakd, *paka;
583     Contact *cont;
584     ContactIDs *ids;
585     int i;
586 
587     if (!ContactIndex (cg, 0) && mode == 3)
588         return;
589 
590     if (mode & 1)
591         SnacCliAddstart (serv);
592 
593     for (i = 0; (cont = ContactIndex (cg, i)); i++)
594         if (!ContactGroupPrefVal (cont->group, CO_ISSBL))
595             SnacCliRosteraddgroup (serv, cont->group, 0);
596 
597     pakd = SnacC (serv, 19, 10, 0, 0);
598     paka = SnacC (serv, 19, 8, 0, 0);
599 
600     for (i = 0; (cont = ContactIndex (cg, i)); i++)
601     {
602         if (cont->ids && (ids = ContactIDHas (cont, roster_normal)) && ids->issbl)
603             SnacCliRosterbulkone (serv, cont->group, cont, pakd, roster_normal, 10);
604         if (ContactPrefVal (cont, CO_WANTSBL))
605             SnacCliRosterbulkone (serv, cont->group, cont, paka, roster_normal, 8);
606     }
607     SnacSend (serv, pakd);
608     SnacSend (serv, paka);
609 
610     if (mode & 2)
611         SnacCliAddend (serv);
612 }
613 
614 /*
615  * SRV_ROSTERADD
616  */
JUMP_SNAC_F(SnacSrvRosteradd)617 JUMP_SNAC_F(SnacSrvRosteradd)
618 {
619 }
620 
621 /*
622  * SRV_ROSTERUPDATE
623  */
JUMP_SNAC_F(SnacSrvRosterupdate)624 JUMP_SNAC_F(SnacSrvRosterupdate)
625 {
626     Server *serv = event->conn->serv;
627     Packet *pak = event->pak;
628     Contact *cont;
629     UWORD tag, id, type, TLVlen;
630     TLV *tlv;
631     strc_t cname;
632     UWORD j;
633 
634     cname  = PacketReadB2Str (pak, NULL);
635     tag    = PacketReadB2 (pak);     /* TAG  */
636     id     = PacketReadB2 (pak);     /* ID   */
637     type   = PacketReadB2 (pak);     /* TYPE */
638     TLVlen = PacketReadB2 (pak);     /* TLV length */
639     tlv    = TLVRead (pak, TLVlen, -1);
640 
641     if (type == roster_normal)
642     {
643         cont = ContactScreen (serv, cname->txt);
644         j = TLVGet (tlv, TLV_NICK);
645         assert (j < 200 || j == (UWORD)-1);
646         if (j != (UWORD)-1 && tlv[j].str.len)
647             ContactAddAlias (cont, ConvFromServ (&tlv[j].str));
648     }
649 
650     TLVD (tlv);
651 
652     if (pak->rpos < pak->len)
653         SnacSrvUnknown (event);
654 }
655 
656 /*
657  * SRV_ROSTERDELETE
658  */
JUMP_SNAC_F(SnacSrvRosterdelete)659 JUMP_SNAC_F(SnacSrvRosterdelete)
660 {
661 }
662 
JUMP_SNAC_F(cb_LoginVisibilitySet)663 static JUMP_SNAC_F(cb_LoginVisibilitySet)
664 {
665     UWORD err;
666 
667     if (!event->pak)
668     {
669         EventD (event);
670         return;
671     }
672     if (event->pak->ref != 19) /* family */
673         return;
674     if (event->pak->cmd != 14) /* command */
675         return;
676 
677     err = PacketReadB2 (event->pak);
678     PacketD (event->pak);
679     event->pak = NULL;
680 
681     if (err)
682         rl_printf (i18n (2325, "Warning: server based contact list change failed with error code %d.\n"), err);
683 }
684 
685 /*
686  * CLI_ROSTERADD/UPDATE - SNAC(13,9)
687  */
SnacCliSetvisibility(Server * serv,char value,char islogin)688 void SnacCliSetvisibility (Server *serv, char value, char islogin)
689 {
690     Packet *pak;
691 
692     if (serv->oscar_privacy_tag)
693     {
694         pak = SnacC (serv, 19, 9, 0, 0);
695         SnacCliRosterbulkdata (pak, "", 0, serv->oscar_privacy_tag, roster_visibility);
696         PacketWriteTLV      (pak, TLV_PRIVACY);
697         PacketWrite1        (pak, value);
698         PacketWriteTLVDone  (pak);
699         PacketWriteBLenDone (pak);
700         SnacSendR (serv, pak, cb_LoginVisibilitySet, NULL);
701         serv->oscar_privacy_value = value;
702     }
703     else
704     {
705         serv->oscar_privacy_tag = rand () % 0x8000;
706         SnacCliRosterentryadd (serv, "", 0, serv->oscar_privacy_tag, roster_visibility, TLV_PRIVACY, &value, 1);
707         serv->oscar_privacy_value = value;
708     }
709 }
710 
711 /*
712  * CLI_ROSTERUPDATE - SNAC(13,9)
713  */
SnacCliSetlastupdate(Server * serv)714 void SnacCliSetlastupdate (Server *serv)
715 {
716     Packet *pak;
717 
718     pak = SnacC (serv, 19, 9, 0, 0);
719     SnacCliRosterbulkdata (pak, "LastUpdateDate", 0, 0x4141, roster_lastupd);
720     PacketWriteTLV      (pak, TLV_LASTUPD);
721     PacketWrite4        (pak, time (NULL));
722     PacketWriteTLVDone  (pak);
723     PacketWriteBLenDone (pak);
724     SnacSend (serv, pak);
725 }
726 
727 /*
728  * CLI_ROSTERDELETE - SNAC(13,a)
729  */
SnacCliRosterdeletegroup(Server * serv,ContactGroup * cg,int mode)730 void SnacCliRosterdeletegroup (Server *serv, ContactGroup *cg, int mode)
731 {
732     Packet *pak;
733 
734     if (mode & 1)
735         SnacCliAddstart (serv);
736     if (cg->id)
737     {
738         pak = SnacC (serv, 19, 10, 0, 0);
739         SnacCliRosterbulkone (serv, cg, NULL, pak, roster_group, 10);
740         SnacSend (serv, pak);
741     }
742     if (mode & 2)
743         SnacCliAddend (serv);
744 }
745 
746 /*
747  * CLI_ROSTERDELETE - SNAC(13,a)
748  */
SnacCliRosterdeletecontact(Server * serv,Contact * cont,int mode)749 void SnacCliRosterdeletecontact (Server *serv, Contact *cont, int mode)
750 {
751     Packet *pak;
752     ContactIDs *ids;
753 
754     if (mode & 1)
755         SnacCliAddstart (serv);
756     if (cont->ids)
757     {
758         pak = SnacC (serv, 19, 10, 0, 0);
759         if ((ids = ContactIDHas (cont, roster_normal)) && ids->issbl)
760             SnacCliRosterbulkone (serv, cont->group, cont, pak, roster_normal, 10);
761         if ((ids = ContactIDHas (cont, roster_invisible)) && ids->issbl)
762             SnacCliRosterbulkone (serv, NULL, cont, pak, roster_invisible, 10);
763         if ((ids = ContactIDHas (cont, roster_visible)) && ids->issbl)
764             SnacCliRosterbulkone (serv, NULL, cont, pak, roster_visible, 10);
765         if ((ids = ContactIDHas (cont, roster_ignore)) && ids->issbl)
766             SnacCliRosterbulkone (serv, NULL, cont, pak, roster_ignore, 10);
767         SnacSend (serv, pak);
768     }
769     if (mode & 2)
770         SnacCliAddend (serv);
771 }
772 
773 /*
774  * CLI_ROSTERDELETE - SNAC(13,a)
775  */
SnacCliRosterentrydelete(Server * serv,RosterEntry * re)776 void SnacCliRosterentrydelete (Server *serv, RosterEntry *re)
777 {
778     Packet *pak;
779     int i;
780 
781     SnacCliAddstart (serv);
782     pak = SnacC (serv, 19, 10, 0, 0);
783     SnacCliRosterbulkdata (pak, re->name, re->tag, re->id, re->type);
784     for (i = 0; i < 16 || re->tlv[i].tag; i++)
785         if (re->tlv[i].tag)
786             PacketWriteTLVData (pak, re->tlv[i].tag, re->tlv[i].str.txt, re->tlv[i].str.len);
787     PacketWriteBLenDone (pak);
788     SnacSend (serv, pak);
789     SnacCliAddend (serv);
790 }
791 
SnacCliRosterdelete(Server * serv,const char * name,UWORD tag,UWORD id,roster_t type)792 void SnacCliRosterdelete (Server *serv, const char *name, UWORD tag, UWORD id, roster_t type)
793 {
794     Packet *pak;
795 
796     SnacCliAddstart (serv);
797     pak = SnacC (serv, 19, 10, 0, 0);
798     SnacCliRosterbulkdata (pak, name, tag, id, type);
799     PacketWriteBLenDone (pak);
800     SnacSend (serv, pak);
801     SnacCliAddend (serv);
802 }
803 
804 /*
805  * SRV_UPDATEACK - SNAC(13,e)
806  */
JUMP_SNAC_F(SnacSrvUpdateack)807 JUMP_SNAC_F(SnacSrvUpdateack)
808 {
809     Server *serv = event->conn->serv;
810     Contact *cont = NULL;
811     Event *event2;
812     UWORD err;
813 
814     if (!PacketReadLeft (event->pak))
815         return;
816 
817     err = PacketReadB2 (event->pak);
818     SnacSrvUpdateack (event);
819 
820     event2 = QueueDequeue (serv->conn, QUEUE_CHANGE_ROSTER, event->pak->ref);
821     cont = event2 ? event2->cont : NULL;
822 
823     switch (err)
824     {
825         case 0xe:
826             if (cont)
827             {
828                 OptSetVal (&cont->copts, CO_ASK_SBL, 1);
829                 OptSetVal (&cont->copts, CO_TO_SBL, 0);
830                 OptSetVal (&cont->copts, CO_FROM_SBL, 0);
831                 OptSetVal (&cont->copts, CO_ISSBL, 0);
832                 SnacCliRosteraddcontact (serv, cont, 3);
833             }
834             break;
835         case 10:
836             if (cont)
837             {
838                 OptSetVal (&cont->copts, CO_ASK_SBL, 1);
839                 OptSetVal (&cont->copts, CO_TO_SBL, 0);
840                 OptSetVal (&cont->copts, CO_FROM_SBL, 0);
841                 OptSetVal (&cont->copts, CO_ISSBL, 0);
842                 rl_printf (i18n (2565, "Contact upload for %s%s%s failed, authorization required.\n"),
843                           COLCONTACT, s_quote (cont->nick), COLNONE);
844             }
845             else
846                 rl_printf (i18n (2537, "Contact upload failed, authorization required.\n"));
847             break;
848         case 3:
849             if (cont)
850             {
851                 rl_printf (i18n (2566, "Contact upload for %s%s%s failed, already on server.\n"),
852                            COLCONTACT, s_quote (cont->nick), COLNONE);
853             }
854             else
855                 rl_printf (i18n (2538, "Contact upload failed, already on server.\n"));
856             break;
857         case 0:
858             if (cont)
859             {
860                 OptSetVal (&cont->copts, CO_ISSBL, 1);
861                 if (!ContactPrefVal (cont, CO_ASK_SBL))
862                 {
863                     OptSetVal (&cont->copts, CO_TO_SBL, 1);
864                     OptSetVal (&cont->copts, CO_FROM_SBL, 1);
865                 }
866                 rl_printf (i18n (2567, "Contact upload for %s%s%s succeeded.\n"),
867                            COLCONTACT, s_quote (cont->nick), COLNONE);
868             }
869             else
870                 rl_printf (i18n (2539, "Contact upload succeeded.\n"));
871             break;
872         default:
873             rl_printf (i18n (2325, "Warning: server based contact list change failed with error code %d.\n"), err);
874     }
875     if (event2)
876         EventD (event2);
877 }
878 
879 /*
880  * SRV_ROSTEROK - SNAC(13,f)
881  */
JUMP_SNAC_F(SnacSrvRosterok)882 JUMP_SNAC_F(SnacSrvRosterok)
883 {
884     /* ignore */
885     Server *serv;
886     Packet *pak;
887     Event *event2;
888     Roster *roster;
889     UWORD count;
890     time_t stmp;
891 
892     if (!event)
893         return;
894 
895     serv = event->conn->serv;
896     if (!serv)
897         return;
898 
899     pak = event->pak;
900     if (!pak)
901         return;
902 
903     event2 = QueueDequeue2 (serv->conn, QUEUE_REQUEST_ROSTER, 0, 0);
904     if (!event2 || !event2->callback)
905     {
906         DebugH (DEB_PROTOCOL, "Unrequested roster packet received.\n");
907         return;
908     }
909 
910     roster = event2->data;
911     if (!roster)
912     {
913         roster = OscarRosterC ();
914         event2->data = roster;
915     }
916 
917     PacketRead1 (pak);
918     count = PacketReadB2 (pak);          /* COUNT */
919     stmp = PacketReadB4 (pak);
920 
921 #if 0
922     if (!roster->import)
923     {
924         time_t now = time (NULL);
925         UDWORD da = now;
926         SnacCliRosterentryadd (serv, "ImportTime", 0, 1, roster_importt, TLV_IMPORT, &da, 4);
927     }
928     if (!roster->ICQTIC)
929         SnacCliRosterentryadd (serv, "ICQTIC", 0, 2, roster_icqtic, TLV_ICQTIC, "3608,0,0,0,60,null", 18);
930     if (!serv->oscar_privacy_tag)
931     {
932         serv->oscar_privacy_tag = rand () % 0x8000;
933         SnacCliRosterentryadd (serv, "", 0, serv->oscar_privacy_tag, roster_visibility, TLV_PRIVACY, "\x03", 1);
934         serv->oscar_privacy_value = 3;
935     }
936 #endif
937     if (~serv->conn->connect & CONNECT_OK)
938         CliFinishLogin (serv);
939 
940     SnacCliRosterack (serv);
941     event2->callback (event2);
942 }
943 
944 /*
945  * SRV_ADDSTART
946  */
JUMP_SNAC_F(SnacSrvAddstart)947 JUMP_SNAC_F(SnacSrvAddstart)
948 {
949     if (event->pak->rpos < event->pak->len)
950         SnacSrvUnknown (event);
951 }
952 
953 /*
954  * SRV_ADDEND
955  */
JUMP_SNAC_F(SnacSrvAddend)956 JUMP_SNAC_F(SnacSrvAddend)
957 {
958     if (event->pak->rpos < event->pak->len)
959         SnacSrvUnknown (event);
960 }
961 
962 
963 /*
964  * CLI_ADDSTART - SNAC(13,11)
965  */
SnacCliAddstart(Server * serv)966 void SnacCliAddstart (Server *serv)
967 {
968     Packet *pak;
969 
970     pak = SnacC (serv, 19, 17, 0, 0);
971     SnacSend (serv, pak);
972 }
973 
974 /*
975  * CLI_ADDEND - SNAC(13,12)
976  */
SnacCliAddend(Server * serv)977 void SnacCliAddend (Server *serv)
978 {
979     Packet *pak;
980 
981     pak = SnacC (serv, 19, 18, 0, 0);
982     SnacSend (serv, pak);
983 }
984 
985 /*
986  * CLI_GRANTAUTH - SNAC(13,14)
987  */
SnacCliGrantauth(Server * serv,Contact * cont)988 void SnacCliGrantauth (Server *serv, Contact *cont)
989 {
990     Packet *pak;
991 
992     if (!cont)
993         return;
994     pak = SnacC (serv, 19, 20, 0, 0);
995     PacketWriteCont (pak, cont);
996     PacketWrite4    (pak, 0);
997     SnacSend (serv, pak);
998 }
999 
1000 /*
1001  * CLI_REQAUTH - SNAC(13,18)
1002  */
SnacCliReqauth(Server * serv,Contact * cont,const char * msg)1003 void SnacCliReqauth (Server *serv, Contact *cont, const char *msg)
1004 {
1005     Packet *pak;
1006 
1007     if (!cont)
1008         return;
1009     pak = SnacC (serv, 19, 24, 0, 0);
1010     PacketWriteCont (pak, cont);
1011     PacketWriteStrB (pak, c_out_to (msg, cont));
1012     PacketWrite2    (pak, 0);
1013     SnacSend (serv, pak);
1014 }
1015 
1016 /*
1017  * SRV_AUTHREQ - SNAC(13,19)
1018  */
JUMP_SNAC_F(SnacSrvAuthreq)1019 JUMP_SNAC_F(SnacSrvAuthreq)
1020 {
1021     Server *serv = event->conn->serv;
1022     Packet *pak;
1023     Contact *cont;
1024     strc_t ctext;
1025     char *text;
1026 
1027     pak   = event->pak;
1028     cont  = PacketReadCont (pak, serv);
1029     ctext = PacketReadB2Str (pak, NULL);
1030 
1031     if (!cont)
1032         return;
1033 
1034     text = strdup (c_in_to_split (ctext, cont));
1035     IMSrvMsg (cont, NOW, CV_ORIGIN_v8, MSG_AUTH_REQ, text);
1036     free (text);
1037 }
1038 
1039 /*
1040  * CLI_AUTHORIZE - SNAC(13,1a)
1041  */
SnacCliAuthorize(Server * serv,Contact * cont,BOOL accept,const char * msg)1042 void SnacCliAuthorize (Server *serv, Contact *cont, BOOL accept, const char *msg)
1043 {
1044     Packet *pak;
1045 
1046     if (!cont)
1047         return;
1048     pak = SnacC (serv, 19, 26, 0, 0);
1049     PacketWriteCont (pak, cont);
1050     PacketWrite1    (pak, accept ? 1 : 0);
1051     PacketWriteStrB (pak, accept ? "" : c_out_to (msg, cont));
1052     SnacSend (serv, pak);
1053 }
1054 
1055 /*
1056  * SRV_AUTHREPLY - SNAC(13,1b)
1057  */
JUMP_SNAC_F(SnacSrvAuthreply)1058 JUMP_SNAC_F(SnacSrvAuthreply)
1059 {
1060     Server *serv = event->conn->serv;
1061     Packet *pak;
1062     Contact *cont;
1063     strc_t ctext;
1064     char *text;
1065     UBYTE acc;
1066 
1067     pak = event->pak;
1068     cont  = PacketReadCont (pak, serv);
1069     acc   = PacketRead1    (pak);
1070     ctext = PacketReadB2Str (pak, NULL);
1071 
1072     if (!cont)
1073         return;
1074 
1075     text = strdup (c_in_to_split (ctext, cont));
1076     IMSrvMsg (cont, NOW, CV_ORIGIN_v8, acc ? MSG_AUTH_GRANT : MSG_AUTH_DENY, text);
1077     free (text);
1078 }
1079 
1080 /*
1081  * SRV_ADDEDYOU - SNAC(13,1c)
1082  */
JUMP_SNAC_F(SnacSrvAddedyou)1083 JUMP_SNAC_F(SnacSrvAddedyou)
1084 {
1085     Contact *cont;
1086 
1087     cont = PacketReadCont (event->pak, event->conn->serv);
1088     IMSrvMsg (cont, NOW, CV_ORIGIN_v8, MSG_AUTH_ADDED, "");
1089 }
1090