source: protocols/oscar/icq.c @ 0b1ae59

Last change on this file since 0b1ae59 was 5ebff60, checked in by dequis <dx@…>, at 2015-02-20T22:50:54Z

Reindent everything to K&R style with tabs

Used uncrustify, with the configuration file in ./doc/uncrustify.cfg

Commit author set to "Indent <please@…>" so that it's easier to
skip while doing git blame.

  • Property mode set to 100644
File size: 10.5 KB
Line 
1/*
2 * Encapsulated ICQ.
3 *
4 */
5
6#include <aim.h>
7#include "icq.h"
8
9int aim_icq_reqofflinemsgs(aim_session_t *sess)
10{
11        aim_conn_t *conn;
12        aim_frame_t *fr;
13        aim_snacid_t snacid;
14        int bslen;
15
16        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) {
17                return -EINVAL;
18        }
19
20        bslen = 2 + 4 + 2 + 2;
21
22        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) {
23                return -ENOMEM;
24        }
25
26        snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
27        aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
28
29        /* For simplicity, don't bother using a tlvlist */
30        aimbs_put16(&fr->data, 0x0001);
31        aimbs_put16(&fr->data, bslen);
32
33        aimbs_putle16(&fr->data, bslen - 2);
34        aimbs_putle32(&fr->data, atoi(sess->sn));
35        aimbs_putle16(&fr->data, 0x003c); /* I command thee. */
36        aimbs_putle16(&fr->data, snacid); /* eh. */
37
38        aim_tx_enqueue(sess, fr);
39
40        return 0;
41}
42
43int aim_icq_ackofflinemsgs(aim_session_t *sess)
44{
45        aim_conn_t *conn;
46        aim_frame_t *fr;
47        aim_snacid_t snacid;
48        int bslen;
49
50        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) {
51                return -EINVAL;
52        }
53
54        bslen = 2 + 4 + 2 + 2;
55
56        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) {
57                return -ENOMEM;
58        }
59
60        snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
61        aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
62
63        /* For simplicity, don't bother using a tlvlist */
64        aimbs_put16(&fr->data, 0x0001);
65        aimbs_put16(&fr->data, bslen);
66
67        aimbs_putle16(&fr->data, bslen - 2);
68        aimbs_putle32(&fr->data, atoi(sess->sn));
69        aimbs_putle16(&fr->data, 0x003e); /* I command thee. */
70        aimbs_putle16(&fr->data, snacid); /* eh. */
71
72        aim_tx_enqueue(sess, fr);
73
74        return 0;
75}
76
77int aim_icq_getallinfo(aim_session_t *sess, const char *uin)
78{
79        aim_conn_t *conn;
80        aim_frame_t *fr;
81        aim_snacid_t snacid;
82        int bslen;
83        struct aim_icq_info *info;
84
85        if (!uin || uin[0] < '0' || uin[0] > '9') {
86                return -EINVAL;
87        }
88
89        if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) {
90                return -EINVAL;
91        }
92
93        bslen = 2 + 4 + 2 + 2 + 2 + 4;
94
95        if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) {
96                return -ENOMEM;
97        }
98
99        snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0);
100        aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid);
101
102        /* For simplicity, don't bother using a tlvlist */
103        aimbs_put16(&fr->data, 0x0001);
104        aimbs_put16(&fr->data, bslen);
105
106        aimbs_putle16(&fr->data, bslen - 2);
107        aimbs_putle32(&fr->data, atoi(sess->sn));
108        aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */
109        aimbs_putle16(&fr->data, snacid); /* eh. */
110        aimbs_putle16(&fr->data, 0x04b2); /* shrug. */
111        aimbs_putle32(&fr->data, atoi(uin));
112
113        aim_tx_enqueue(sess, fr);
114
115        /* Keep track of this request and the ICQ number and request ID */
116        info = g_new0(struct aim_icq_info, 1);
117        info->reqid = snacid;
118        info->uin = atoi(uin);
119        info->next = sess->icq_info;
120        sess->icq_info = info;
121
122        return 0;
123}
124
125static void aim_icq_freeinfo(struct aim_icq_info *info)
126{
127        int i;
128
129        if (!info) {
130                return;
131        }
132        g_free(info->nick);
133        g_free(info->first);
134        g_free(info->last);
135        g_free(info->email);
136        g_free(info->homecity);
137        g_free(info->homestate);
138        g_free(info->homephone);
139        g_free(info->homefax);
140        g_free(info->homeaddr);
141        g_free(info->mobile);
142        g_free(info->homezip);
143        g_free(info->personalwebpage);
144        if (info->email2) {
145                for (i = 0; i < info->numaddresses; i++) {
146                        g_free(info->email2[i]);
147                }
148        }
149        g_free(info->email2);
150        g_free(info->workcity);
151        g_free(info->workstate);
152        g_free(info->workphone);
153        g_free(info->workfax);
154        g_free(info->workaddr);
155        g_free(info->workzip);
156        g_free(info->workcompany);
157        g_free(info->workdivision);
158        g_free(info->workposition);
159        g_free(info->workwebpage);
160        g_free(info->info);
161        g_free(info);
162}
163
164/**
165 * Subtype 0x0003 - Response to 0x0015/0x002, contains an ICQesque packet.
166 */
167static int icqresponse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
168{
169        int ret = 0;
170        aim_tlvlist_t *tl;
171        aim_tlv_t *datatlv;
172        aim_bstream_t qbs;
173        guint16 cmd, reqid;
174
175        if (!(tl = aim_readtlvchain(bs)) || !(datatlv = aim_gettlv(tl, 0x0001, 1))) {
176                aim_freetlvchain(&tl);
177                imcb_error(sess->aux_data, "corrupt ICQ response\n");
178                return 0;
179        }
180
181        aim_bstream_init(&qbs, datatlv->value, datatlv->length);
182
183        aimbs_getle16(&qbs); /* cmdlen */
184        aimbs_getle32(&qbs); /* ouruin */
185        cmd = aimbs_getle16(&qbs);
186        reqid = aimbs_getle16(&qbs);
187
188        if (cmd == 0x0041) { /* offline message */
189                guint16 msglen;
190                struct aim_icq_offlinemsg msg;
191                aim_rxcallback_t userfunc;
192
193                memset(&msg, 0, sizeof(msg));
194
195                msg.sender = aimbs_getle32(&qbs);
196                msg.year = aimbs_getle16(&qbs);
197                msg.month = aimbs_getle8(&qbs);
198                msg.day = aimbs_getle8(&qbs);
199                msg.hour = aimbs_getle8(&qbs);
200                msg.minute = aimbs_getle8(&qbs);
201                msg.type = aimbs_getle16(&qbs);
202                msglen = aimbs_getle16(&qbs);
203                msg.msg = aimbs_getstr(&qbs, msglen);
204
205                if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG))) {
206                        ret = userfunc(sess, rx, &msg);
207                }
208
209                g_free(msg.msg);
210
211        } else if (cmd == 0x0042) {
212                aim_rxcallback_t userfunc;
213
214                if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE))) {
215                        ret = userfunc(sess, rx);
216                }
217        } else if (cmd == 0x07da) { /* information */
218                guint16 subtype;
219                struct aim_icq_info *info;
220                aim_rxcallback_t userfunc;
221
222                subtype = aimbs_getle16(&qbs);
223                aim_bstream_advance(&qbs, 1); /* 0x0a */
224
225                /* find another data from the same request */
226                for (info = sess->icq_info; info && (info->reqid != reqid); info = info->next) {
227                        ;
228                }
229
230                if (!info) {
231                        info = g_new0(struct aim_icq_info, 1);
232                        info->reqid = reqid;
233                        info->next = sess->icq_info;
234                        sess->icq_info = info;
235                }
236
237                switch (subtype) {
238                case 0x00a0: {         /* hide ip status */
239                        /* nothing */
240                } break;
241                case 0x00aa: {         /* password change status */
242                        /* nothing */
243                } break;
244                case 0x00c8: {         /* general and "home" information */
245                        info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
246                        info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
247                        info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
248                        info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
249                        info->homecity = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
250                        info->homestate = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
251                        info->homephone = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
252                        info->homefax = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
253                        info->homeaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
254                        info->mobile = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
255                        info->homezip = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
256                        info->homecountry = aimbs_getle16(&qbs);
257                        /* 0x0a 00 02 00 */
258                        /* 1 byte timezone? */
259                        /* 1 byte hide email flag? */
260                } break;
261                case 0x00dc: {         /* personal information */
262                        info->age = aimbs_getle8(&qbs);
263                        info->unknown = aimbs_getle8(&qbs);
264                        info->gender = aimbs_getle8(&qbs);
265                        info->personalwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
266                        info->birthyear = aimbs_getle16(&qbs);
267                        info->birthmonth = aimbs_getle8(&qbs);
268                        info->birthday = aimbs_getle8(&qbs);
269                        info->language1 = aimbs_getle8(&qbs);
270                        info->language2 = aimbs_getle8(&qbs);
271                        info->language3 = aimbs_getle8(&qbs);
272                        /* 0x00 00 01 00 00 01 00 00 00 00 00 */
273                } break;
274                case 0x00d2: {         /* work information */
275                        info->workcity = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
276                        info->workstate = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
277                        info->workphone = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
278                        info->workfax = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
279                        info->workaddr = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
280                        info->workzip = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
281                        info->workcountry = aimbs_getle16(&qbs);
282                        info->workcompany = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
283                        info->workdivision = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
284                        info->workposition = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
285                        aim_bstream_advance(&qbs, 2);                                  /* 0x01 00 */
286                        info->workwebpage = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
287                } break;
288                case 0x00e6: {         /* additional personal information */
289                        info->info = aimbs_getstr(&qbs, aimbs_getle16(&qbs) - 1);
290                } break;
291                case 0x00eb: {         /* email address(es) */
292                        int i;
293                        info->numaddresses = aimbs_getle16(&qbs);
294                        info->email2 = g_new0(char *, info->numaddresses);
295                        for (i = 0; i < info->numaddresses; i++) {
296                                info->email2[i] = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
297                                if (i + 1 != info->numaddresses) {
298                                        aim_bstream_advance(&qbs, 1);                                  /* 0x00 */
299                                }
300                        }
301                } break;
302                case 0x00f0: {         /* personal interests */
303                } break;
304                case 0x00fa: {         /* past background and current organizations */
305                } break;
306                case 0x0104: {         /* alias info */
307                        info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
308                        info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
309                        info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
310                        aim_bstream_advance(&qbs, aimbs_getle16(&qbs));
311                        /* email address? */
312                        /* Then 0x00 02 00 */
313                } break;
314                case 0x010e: {         /* unknown */
315                        /* 0x00 00 */
316                } break;
317
318                case 0x019a: {         /* simple info */
319                        aim_bstream_advance(&qbs, 2);
320                        info->uin = aimbs_getle32(&qbs);
321                        info->nick = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
322                        info->first = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
323                        info->last = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
324                        info->email = aimbs_getstr(&qbs, aimbs_getle16(&qbs));
325                        /* Then 0x00 02 00 00 00 00 00 */
326                } break;
327                } /* End switch statement */
328
329
330                if (!(snac->flags & 0x0001)) {
331                        if (subtype != 0x0104) {
332                                if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_INFO))) {
333                                        ret = userfunc(sess, rx, info);
334                                }
335                        }
336
337                        /* Bitlbee - not supported, yet
338                        if (info->uin && info->nick)
339                                if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_ALIAS)))
340                                        ret = userfunc(sess, rx, info);
341                        */
342
343                        if (sess->icq_info == info) {
344                                sess->icq_info = info->next;
345                        } else {
346                                struct aim_icq_info *cur;
347                                for (cur = sess->icq_info; (cur->next && (cur->next != info)); cur = cur->next) {
348                                        ;
349                                }
350                                if (cur->next) {
351                                        cur->next = cur->next->next;
352                                }
353                        }
354                        aim_icq_freeinfo(info);
355                }
356        }
357
358        aim_freetlvchain(&tl);
359
360        return ret;
361}
362
363static int snachandler(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs)
364{
365
366        if (snac->subtype == 0x0003) {
367                return icqresponse(sess, mod, rx, snac, bs);
368        }
369
370        return 0;
371}
372
373int icq_modfirst(aim_session_t *sess, aim_module_t *mod)
374{
375
376        mod->family = 0x0015;
377        mod->version = 0x0001;
378        mod->toolid = 0x0110;
379        mod->toolversion = 0x047c;
380        mod->flags = 0;
381        strncpy(mod->name, "icq", sizeof(mod->name));
382        mod->snachandler = snachandler;
383
384        return 0;
385}
386
387
Note: See TracBrowser for help on using the repository browser.