comparison libpurple/protocols/oscar/family_icq.c @ 30362:879baaf87aa2

Added an error handler for family_icq.c. So far it works for icq fullinfo and alias requests. This was originally motivated by me getting "Server rate limit exceeded" while testing authorization requests. This error completely prevented the authorization request dialog from showing up.
author ivan.komarov@soc.pidgin.im
date Sun, 30 May 2010 19:01:30 +0000
parents 9881f18b95b1
children a347a4cd1caf
comparison
equal deleted inserted replaced
30361:9881f18b95b1 30362:879baaf87aa2
23 * 23 *
24 */ 24 */
25 25
26 #include "oscar.h" 26 #include "oscar.h"
27 27
28 int 28 #define AIM_ICQ_INFO_REQUEST 0x04b2
29 aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware) 29 #define AIM_ICQ_ALIAS_REQUEST 0x04ba
30 { 30
31 FlapConnection *conn; 31 static
32 ByteStream bs; 32 int compare_icq_infos(gconstpointer a, gconstpointer b)
33 aim_snacid_t snacid; 33 {
34 int bslen; 34 const struct aim_icq_info* aa = a;
35 35 const guint16* bb = b;
36 if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ))) 36 return aa->reqid - *bb;
37 return -EINVAL;
38
39 bslen = 2+4+2+2+2+2+2+1+1+1+1+1+1;
40
41 byte_stream_new(&bs, 4 + bslen);
42
43 snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
44
45 /* For simplicity, don't bother using a tlvlist */
46 byte_stream_put16(&bs, 0x0001);
47 byte_stream_put16(&bs, bslen);
48
49 byte_stream_putle16(&bs, bslen - 2);
50 byte_stream_putuid(&bs, od);
51 byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
52 byte_stream_putle16(&bs, snacid); /* eh. */
53 byte_stream_putle16(&bs, 0x0c3a); /* shrug. */
54 byte_stream_putle16(&bs, 0x030c);
55 byte_stream_putle16(&bs, 0x0001);
56 byte_stream_putle8(&bs, webaware);
57 byte_stream_putle8(&bs, 0xf8);
58 byte_stream_putle8(&bs, 0x02);
59 byte_stream_putle8(&bs, 0x01);
60 byte_stream_putle8(&bs, 0x00);
61 byte_stream_putle8(&bs, !auth_required);
62
63 flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
64
65 byte_stream_destroy(&bs);
66
67 return 0;
68 }
69
70 /**
71 * Change your ICQ password.
72 *
73 * @param od The oscar session
74 * @param passwd The new password. If this is longer than 8 characters it
75 * will be truncated.
76 * @return Return 0 if no errors, otherwise return the error number.
77 */
78 int aim_icq_changepasswd(OscarData *od, const char *passwd)
79 {
80 FlapConnection *conn;
81 ByteStream bs;
82 aim_snacid_t snacid;
83 int bslen, passwdlen;
84
85 if (!passwd)
86 return -EINVAL;
87
88 if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
89 return -EINVAL;
90
91 passwdlen = strlen(passwd);
92 if (passwdlen > MAXICQPASSLEN)
93 passwdlen = MAXICQPASSLEN;
94 bslen = 2+4+2+2+2+2+passwdlen+1;
95
96 byte_stream_new(&bs, 4 + bslen);
97
98 snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
99
100 /* For simplicity, don't bother using a tlvlist */
101 byte_stream_put16(&bs, 0x0001);
102 byte_stream_put16(&bs, bslen);
103
104 byte_stream_putle16(&bs, bslen - 2);
105 byte_stream_putuid(&bs, od);
106 byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
107 byte_stream_putle16(&bs, snacid); /* eh. */
108 byte_stream_putle16(&bs, 0x042e); /* shrug. */
109 byte_stream_putle16(&bs, passwdlen+1);
110 byte_stream_putraw(&bs, (const guint8 *)passwd, passwdlen);
111 byte_stream_putle8(&bs, '\0');
112
113 flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
114
115 byte_stream_destroy(&bs);
116
117 return 0;
118 }
119
120 int aim_icq_getallinfo(OscarData *od, const char *uin)
121 {
122 FlapConnection *conn;
123 ByteStream bs;
124 aim_snacid_t snacid;
125 int bslen;
126 struct aim_icq_info *info;
127
128 if (!uin || uin[0] < '0' || uin[0] > '9')
129 return -EINVAL;
130
131 if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
132 return -EINVAL;
133
134 bslen = 2 + 4 + 2 + 2 + 2 + 4;
135
136 byte_stream_new(&bs, 4 + bslen);
137
138 snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
139
140 /* For simplicity, don't bother using a tlvlist */
141 byte_stream_put16(&bs, 0x0001);
142 byte_stream_put16(&bs, bslen);
143
144 byte_stream_putle16(&bs, bslen - 2);
145 byte_stream_putuid(&bs, od);
146 byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
147 byte_stream_putle16(&bs, snacid); /* eh. */
148 byte_stream_putle16(&bs, 0x04b2); /* shrug. */
149 byte_stream_putle32(&bs, atoi(uin));
150
151 flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
152
153 byte_stream_destroy(&bs);
154
155 /* Keep track of this request and the ICQ number and request ID */
156 info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
157 info->reqid = snacid;
158 info->uin = atoi(uin);
159 info->next = od->icq_info;
160 od->icq_info = info;
161
162 return 0;
163 }
164
165 int aim_icq_getalias(OscarData *od, const char *uin, gboolean for_auth_request, char *auth_request_reason)
166 {
167 FlapConnection *conn;
168 ByteStream bs;
169 aim_snacid_t snacid;
170 int bslen;
171 struct aim_icq_info *info;
172
173 if (!uin || uin[0] < '0' || uin[0] > '9')
174 return -EINVAL;
175
176 if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
177 return -EINVAL;
178
179 purple_debug_info("oscar", "Requesting ICQ alias for %s\n", uin);
180
181 bslen = 2 + 4 + 2 + 2 + 2 + 4;
182
183 byte_stream_new(&bs, 4 + bslen);
184
185 snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
186
187 /* For simplicity, don't bother using a tlvlist */
188 byte_stream_put16(&bs, 0x0001);
189 byte_stream_put16(&bs, bslen);
190
191 byte_stream_putle16(&bs, bslen - 2);
192 byte_stream_putuid(&bs, od);
193 byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
194 byte_stream_putle16(&bs, snacid); /* eh. */
195 byte_stream_putle16(&bs, 0x04ba); /* shrug. */
196 byte_stream_putle32(&bs, atoi(uin));
197
198 flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
199
200 byte_stream_destroy(&bs);
201
202 /* Keep track of this request and the ICQ number and request ID */
203 info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
204 info->reqid = snacid;
205 info->uin = atoi(uin);
206 info->next = od->icq_info;
207 info->for_auth_request = for_auth_request;
208 info->auth_request_reason = g_strdup(auth_request_reason);
209 od->icq_info = info;
210
211 return 0;
212 }
213
214 /*
215 * Send an SMS message. This is the non-US way. The US-way is to IM
216 * their cell phone number (+19195551234).
217 *
218 * We basically construct and send an XML message. The format is:
219 * <icq_sms_message>
220 * <destination>full_phone_without_leading_+</destination>
221 * <text>message</text>
222 * <codepage>1252</codepage>
223 * <senders_UIN>self_uin</senders_UIN>
224 * <senders_name>self_name</senders_name>
225 * <delivery_receipt>Yes|No</delivery_receipt>
226 * <time>Wkd, DD Mmm YYYY HH:MM:SS TMZ</time>
227 * </icq_sms_message>
228 *
229 * Yeah hi Peter, whaaaat's happening. If there's any way to use
230 * a codepage other than 1252 that would be great. Thaaaanks.
231 */
232 int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char *alias)
233 {
234 FlapConnection *conn;
235 PurpleAccount *account;
236 ByteStream bs;
237 aim_snacid_t snacid;
238 int bslen, xmllen;
239 char *xml;
240 const char *timestr, *username;
241 time_t t;
242 struct tm *tm;
243 gchar *stripped;
244
245 if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
246 return -EINVAL;
247
248 if (!name || !msg || !alias)
249 return -EINVAL;
250
251 account = purple_connection_get_account(od->gc);
252 username = purple_account_get_username(account);
253
254 time(&t);
255 tm = gmtime(&t);
256 timestr = purple_utf8_strftime("%a, %d %b %Y %T %Z", tm);
257
258 stripped = purple_markup_strip_html(msg);
259
260 /* The length of xml included the null terminating character */
261 xmllen = 209 + strlen(name) + strlen(stripped) + strlen(username) + strlen(alias) + strlen(timestr) + 1;
262
263 xml = g_new(char, xmllen);
264 snprintf(xml, xmllen, "<icq_sms_message>"
265 "<destination>%s</destination>"
266 "<text>%s</text>"
267 "<codepage>1252</codepage>"
268 "<senders_UIN>%s</senders_UIN>"
269 "<senders_name>%s</senders_name>"
270 "<delivery_receipt>Yes</delivery_receipt>"
271 "<time>%s</time>"
272 "</icq_sms_message>",
273 name, stripped, username, alias, timestr);
274
275 bslen = 36 + xmllen;
276
277 byte_stream_new(&bs, 4 + bslen);
278
279 snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
280
281 /* For simplicity, don't bother using a tlvlist */
282 byte_stream_put16(&bs, 0x0001);
283 byte_stream_put16(&bs, bslen);
284
285 byte_stream_putle16(&bs, bslen - 2);
286 byte_stream_putuid(&bs, od);
287 byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
288 byte_stream_putle16(&bs, snacid); /* eh. */
289
290 /* From libicq200-0.3.2/src/SNAC-SRV.cpp */
291 byte_stream_putle16(&bs, 0x1482);
292 byte_stream_put16(&bs, 0x0001);
293 byte_stream_put16(&bs, 0x0016);
294 byte_stream_put32(&bs, 0x00000000);
295 byte_stream_put32(&bs, 0x00000000);
296 byte_stream_put32(&bs, 0x00000000);
297 byte_stream_put32(&bs, 0x00000000);
298
299 byte_stream_put16(&bs, 0x0000);
300 byte_stream_put16(&bs, xmllen);
301 byte_stream_putstr(&bs, xml);
302 byte_stream_put8(&bs, 0x00);
303
304 flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
305
306 byte_stream_destroy(&bs);
307
308 g_free(xml);
309 g_free(stripped);
310
311 return 0;
312 }
313
314 static int
315 gotalias(OscarData *od, struct aim_icq_info *info)
316 {
317 PurpleConnection *gc = od->gc;
318 PurpleAccount *account = purple_connection_get_account(gc);
319 gchar who[16], *utf8;
320 PurpleBuddy *b;
321
322 if (info->nick[0] && (utf8 = oscar_utf8_try_convert(account, od, info->nick))) {
323 if (info->for_auth_request) {
324 oscar_auth_recvrequest(gc, g_strdup_printf("%u", info->uin), utf8, info->auth_request_reason);
325 } else {
326 g_snprintf(who, sizeof(who), "%u", info->uin);
327 serv_got_alias(gc, who, utf8);
328 if ((b = purple_find_buddy(account, who))) {
329 purple_blist_node_set_string((PurpleBlistNode*)b, "servernick", utf8);
330 }
331 g_free(utf8);
332 }
333 }
334
335 g_free(info->auth_request_reason);
336 return 1;
337 } 37 }
338 38
339 static void aim_icq_freeinfo(struct aim_icq_info *info) { 39 static void aim_icq_freeinfo(struct aim_icq_info *info) {
340 int i; 40 int i;
341 41
367 g_free(info->workdivision); 67 g_free(info->workdivision);
368 g_free(info->workposition); 68 g_free(info->workposition);
369 g_free(info->workwebpage); 69 g_free(info->workwebpage);
370 g_free(info->info); 70 g_free(info->info);
371 g_free(info->status_note_title); 71 g_free(info->status_note_title);
372 g_free(info); 72 g_free(info->auth_request_reason);
73 }
74
75 static
76 int error(OscarData *od, aim_modsnac_t *error_snac, ByteStream *bs)
77 {
78 aim_snac_t *original_snac = aim_remsnac(od, error_snac->id);
79 guint16 *request_type;
80 GSList *original_info_ptr;
81 struct aim_icq_info *original_info;
82 guint16 reason;
83 gchar *uin;
84
85 if (!original_snac || (original_snac->family != SNAC_FAMILY_ICQ) || !original_snac->data) {
86 purple_debug_misc("oscar", "icq: the original snac for the error packet was not found");
87 g_free(original_snac);
88 return 0;
89 }
90
91 request_type = original_snac->data;
92 original_info_ptr = g_slist_find_custom(od->icq_info, &original_snac->id, compare_icq_infos);
93 original_info = original_info_ptr->data;
94
95 if (!original_info_ptr) {
96 purple_debug_misc("oscar", "icq: the request info for the error packet was not found");
97 g_free(original_snac);
98 return 0;
99 }
100
101 reason = byte_stream_get16(bs);
102 uin = g_strdup_printf("%u", original_info->uin);
103 switch (*request_type) {
104 case AIM_ICQ_INFO_REQUEST:
105 oscar_user_info_display_error(od, reason, uin);
106 break;
107 case AIM_ICQ_ALIAS_REQUEST:
108 /* Couldn't retrieve an alias for the buddy requesting authorization; have to make do with UIN only. */
109 if (original_info->for_auth_request)
110 oscar_auth_recvrequest(od->gc, uin, NULL, original_info->auth_request_reason);
111 break;
112 default:
113 purple_debug_misc("oscar", "icq: got an error packet with unknown request type %u", *request_type);
114 break;
115 }
116
117 aim_icq_freeinfo(original_info);
118 od->icq_info = g_slist_remove(od->icq_info, original_info_ptr);
119 g_free(original_snac->data);
120 g_free(original_snac);
121 return 1;
122 }
123
124 int
125 aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware)
126 {
127 FlapConnection *conn;
128 ByteStream bs;
129 aim_snacid_t snacid;
130 int bslen;
131
132 if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
133 return -EINVAL;
134
135 bslen = 2+4+2+2+2+2+2+1+1+1+1+1+1;
136
137 byte_stream_new(&bs, 4 + bslen);
138
139 snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
140
141 /* For simplicity, don't bother using a tlvlist */
142 byte_stream_put16(&bs, 0x0001);
143 byte_stream_put16(&bs, bslen);
144
145 byte_stream_putle16(&bs, bslen - 2);
146 byte_stream_putuid(&bs, od);
147 byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
148 byte_stream_putle16(&bs, snacid); /* eh. */
149 byte_stream_putle16(&bs, 0x0c3a); /* shrug. */
150 byte_stream_putle16(&bs, 0x030c);
151 byte_stream_putle16(&bs, 0x0001);
152 byte_stream_putle8(&bs, webaware);
153 byte_stream_putle8(&bs, 0xf8);
154 byte_stream_putle8(&bs, 0x02);
155 byte_stream_putle8(&bs, 0x01);
156 byte_stream_putle8(&bs, 0x00);
157 byte_stream_putle8(&bs, !auth_required);
158
159 flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
160
161 byte_stream_destroy(&bs);
162
163 return 0;
164 }
165
166 /**
167 * Change your ICQ password.
168 *
169 * @param od The oscar session
170 * @param passwd The new password. If this is longer than 8 characters it
171 * will be truncated.
172 * @return Return 0 if no errors, otherwise return the error number.
173 */
174 int aim_icq_changepasswd(OscarData *od, const char *passwd)
175 {
176 FlapConnection *conn;
177 ByteStream bs;
178 aim_snacid_t snacid;
179 int bslen, passwdlen;
180
181 if (!passwd)
182 return -EINVAL;
183
184 if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
185 return -EINVAL;
186
187 passwdlen = strlen(passwd);
188 if (passwdlen > MAXICQPASSLEN)
189 passwdlen = MAXICQPASSLEN;
190 bslen = 2+4+2+2+2+2+passwdlen+1;
191
192 byte_stream_new(&bs, 4 + bslen);
193
194 snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
195
196 /* For simplicity, don't bother using a tlvlist */
197 byte_stream_put16(&bs, 0x0001);
198 byte_stream_put16(&bs, bslen);
199
200 byte_stream_putle16(&bs, bslen - 2);
201 byte_stream_putuid(&bs, od);
202 byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
203 byte_stream_putle16(&bs, snacid); /* eh. */
204 byte_stream_putle16(&bs, 0x042e); /* shrug. */
205 byte_stream_putle16(&bs, passwdlen+1);
206 byte_stream_putraw(&bs, (const guint8 *)passwd, passwdlen);
207 byte_stream_putle8(&bs, '\0');
208
209 flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
210
211 byte_stream_destroy(&bs);
212
213 return 0;
214 }
215
216 int aim_icq_getallinfo(OscarData *od, const char *uin)
217 {
218 FlapConnection *conn;
219 ByteStream bs;
220 aim_snacid_t snacid;
221 int bslen;
222 struct aim_icq_info *info;
223 guint16 request_type = AIM_ICQ_INFO_REQUEST;
224
225 if (!uin || uin[0] < '0' || uin[0] > '9')
226 return -EINVAL;
227
228 if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
229 return -EINVAL;
230
231 bslen = 2 + 4 + 2 + 2 + 2 + 4;
232
233 byte_stream_new(&bs, 4 + bslen);
234
235 snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type));
236
237 /* For simplicity, don't bother using a tlvlist */
238 byte_stream_put16(&bs, 0x0001);
239 byte_stream_put16(&bs, bslen);
240
241 byte_stream_putle16(&bs, bslen - 2);
242 byte_stream_putuid(&bs, od);
243 byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
244 byte_stream_putle16(&bs, snacid); /* eh. */
245 byte_stream_putle16(&bs, request_type); /* shrug. */
246 byte_stream_putle32(&bs, atoi(uin));
247
248 flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
249
250 byte_stream_destroy(&bs);
251
252 /* Keep track of this request and the ICQ number and request ID */
253 info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
254 info->reqid = snacid;
255 info->uin = atoi(uin);
256 od->icq_info = g_slist_prepend(od->icq_info, info);
257
258 return 0;
259 }
260
261 int aim_icq_getalias(OscarData *od, const char *uin, gboolean for_auth_request, char *auth_request_reason)
262 {
263 FlapConnection *conn;
264 ByteStream bs;
265 aim_snacid_t snacid;
266 int bslen;
267 struct aim_icq_info *info;
268 guint16 request_type = AIM_ICQ_ALIAS_REQUEST;
269
270 if (!uin || uin[0] < '0' || uin[0] > '9')
271 return -EINVAL;
272
273 if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
274 return -EINVAL;
275
276 purple_debug_info("oscar", "Requesting ICQ alias for %s\n", uin);
277
278 bslen = 2 + 4 + 2 + 2 + 2 + 4;
279
280 byte_stream_new(&bs, 4 + bslen);
281
282 snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, &request_type, sizeof(request_type));
283
284 /* For simplicity, don't bother using a tlvlist */
285 byte_stream_put16(&bs, 0x0001);
286 byte_stream_put16(&bs, bslen);
287
288 byte_stream_putle16(&bs, bslen - 2);
289 byte_stream_putuid(&bs, od);
290 byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
291 byte_stream_putle16(&bs, snacid); /* eh. */
292 byte_stream_putle16(&bs, request_type); /* shrug. */
293 byte_stream_putle32(&bs, atoi(uin));
294
295 flap_connection_send_snac_with_priority(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs, FALSE);
296
297 byte_stream_destroy(&bs);
298
299 /* Keep track of this request and the ICQ number and request ID */
300 info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
301 info->reqid = snacid;
302 info->uin = atoi(uin);
303 info->for_auth_request = for_auth_request;
304 info->auth_request_reason = g_strdup(auth_request_reason);
305 od->icq_info = g_slist_prepend(od->icq_info, info);
306
307 return 0;
308 }
309
310 /*
311 * Send an SMS message. This is the non-US way. The US-way is to IM
312 * their cell phone number (+19195551234).
313 *
314 * We basically construct and send an XML message. The format is:
315 * <icq_sms_message>
316 * <destination>full_phone_without_leading_+</destination>
317 * <text>message</text>
318 * <codepage>1252</codepage>
319 * <senders_UIN>self_uin</senders_UIN>
320 * <senders_name>self_name</senders_name>
321 * <delivery_receipt>Yes|No</delivery_receipt>
322 * <time>Wkd, DD Mmm YYYY HH:MM:SS TMZ</time>
323 * </icq_sms_message>
324 *
325 * Yeah hi Peter, whaaaat's happening. If there's any way to use
326 * a codepage other than 1252 that would be great. Thaaaanks.
327 */
328 int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char *alias)
329 {
330 FlapConnection *conn;
331 PurpleAccount *account;
332 ByteStream bs;
333 aim_snacid_t snacid;
334 int bslen, xmllen;
335 char *xml;
336 const char *timestr, *username;
337 time_t t;
338 struct tm *tm;
339 gchar *stripped;
340
341 if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ICQ)))
342 return -EINVAL;
343
344 if (!name || !msg || !alias)
345 return -EINVAL;
346
347 account = purple_connection_get_account(od->gc);
348 username = purple_account_get_username(account);
349
350 time(&t);
351 tm = gmtime(&t);
352 timestr = purple_utf8_strftime("%a, %d %b %Y %T %Z", tm);
353
354 stripped = purple_markup_strip_html(msg);
355
356 /* The length of xml included the null terminating character */
357 xmllen = 209 + strlen(name) + strlen(stripped) + strlen(username) + strlen(alias) + strlen(timestr) + 1;
358
359 xml = g_new(char, xmllen);
360 snprintf(xml, xmllen, "<icq_sms_message>"
361 "<destination>%s</destination>"
362 "<text>%s</text>"
363 "<codepage>1252</codepage>"
364 "<senders_UIN>%s</senders_UIN>"
365 "<senders_name>%s</senders_name>"
366 "<delivery_receipt>Yes</delivery_receipt>"
367 "<time>%s</time>"
368 "</icq_sms_message>",
369 name, stripped, username, alias, timestr);
370
371 bslen = 36 + xmllen;
372
373 byte_stream_new(&bs, 4 + bslen);
374
375 snacid = aim_cachesnac(od, SNAC_FAMILY_ICQ, 0x0002, 0x0000, NULL, 0);
376
377 /* For simplicity, don't bother using a tlvlist */
378 byte_stream_put16(&bs, 0x0001);
379 byte_stream_put16(&bs, bslen);
380
381 byte_stream_putle16(&bs, bslen - 2);
382 byte_stream_putuid(&bs, od);
383 byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
384 byte_stream_putle16(&bs, snacid); /* eh. */
385
386 /* From libicq200-0.3.2/src/SNAC-SRV.cpp */
387 byte_stream_putle16(&bs, 0x1482);
388 byte_stream_put16(&bs, 0x0001);
389 byte_stream_put16(&bs, 0x0016);
390 byte_stream_put32(&bs, 0x00000000);
391 byte_stream_put32(&bs, 0x00000000);
392 byte_stream_put32(&bs, 0x00000000);
393 byte_stream_put32(&bs, 0x00000000);
394
395 byte_stream_put16(&bs, 0x0000);
396 byte_stream_put16(&bs, xmllen);
397 byte_stream_putstr(&bs, xml);
398 byte_stream_put8(&bs, 0x00);
399
400 flap_connection_send_snac(od, conn, SNAC_FAMILY_ICQ, 0x0002, 0x0000, snacid, &bs);
401
402 byte_stream_destroy(&bs);
403
404 g_free(xml);
405 g_free(stripped);
406
407 return 0;
408 }
409
410 static int
411 gotalias(OscarData *od, struct aim_icq_info *info)
412 {
413 PurpleConnection *gc = od->gc;
414 PurpleAccount *account = purple_connection_get_account(gc);
415 gchar who[16], *utf8;
416 PurpleBuddy *b;
417
418 if (info->nick[0] && (utf8 = oscar_utf8_try_convert(account, od, info->nick))) {
419 if (info->for_auth_request) {
420 oscar_auth_recvrequest(gc, g_strdup_printf("%u", info->uin), utf8, info->auth_request_reason);
421 } else {
422 g_snprintf(who, sizeof(who), "%u", info->uin);
423 serv_got_alias(gc, who, utf8);
424 if ((b = purple_find_buddy(account, who))) {
425 purple_blist_node_set_string((PurpleBlistNode*)b, "servernick", utf8);
426 }
427 g_free(utf8);
428 }
429 }
430 return 1;
373 } 431 }
374 432
375 /** 433 /**
376 * Subtype 0x0003 - Response to SNAC_FAMILY_ICQ/0x002, contains an ICQesque packet. 434 * Subtype 0x0003 - Response to SNAC_FAMILY_ICQ/0x002, contains an ICQesque packet.
377 */ 435 */
378 static int 436 static int
379 icqresponse(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) 437 icqresponse(OscarData *od, aim_modsnac_t *snac, ByteStream *bs)
380 { 438 {
381 int ret = 0;
382 GSList *tlvlist; 439 GSList *tlvlist;
383 aim_tlv_t *datatlv; 440 aim_tlv_t *datatlv;
384 ByteStream qbs; 441 ByteStream qbs;
385 guint32 ouruin; 442 guint32 ouruin;
386 guint16 cmdlen, cmd, reqid; 443 guint16 cmdlen, cmd, reqid;
400 457
401 purple_debug_misc("oscar", "icq response: %d bytes, %u, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid); 458 purple_debug_misc("oscar", "icq response: %d bytes, %u, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid);
402 459
403 if (cmd == 0x07da) { /* information */ 460 if (cmd == 0x07da) { /* information */
404 guint16 subtype; 461 guint16 subtype;
462 GSList *info_ptr;
405 struct aim_icq_info *info; 463 struct aim_icq_info *info;
406 464
407 subtype = byte_stream_getle16(&qbs); 465 subtype = byte_stream_getle16(&qbs);
408 byte_stream_advance(&qbs, 1); /* 0x0a */ 466 byte_stream_advance(&qbs, 1); /* 0x0a */
409 467
410 /* find other data from the same request */ 468 /* find other data from the same request */
411 for (info = od->icq_info; info && (info->reqid != reqid); info = info->next); 469 info_ptr = g_slist_find_custom(od->icq_info, &reqid, compare_icq_infos);
412 if (!info) { 470 if (!info_ptr) {
413 info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1); 471 struct aim_icq_info *new_info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
414 info->reqid = reqid; 472 new_info->reqid = reqid;
415 info->next = od->icq_info; 473 info_ptr = od->icq_info = g_slist_prepend(od->icq_info, new_info);
416 od->icq_info = info;
417 } 474 }
418 475
476 info = info_ptr->data;
419 switch (subtype) { 477 switch (subtype) {
420 case 0x00a0: { /* hide ip status */ 478 case 0x00a0: { /* hide ip status */
421 /* nothing */ 479 /* nothing */
422 } break; 480 } break;
423 481
665 info->uin = atoi(uin); 723 info->uin = atoi(uin);
666 info->status_note_title = status_note_title; 724 info->status_note_title = status_note_title;
667 725
668 memcpy(&info->icbm_cookie, cookie, 8); 726 memcpy(&info->icbm_cookie, cookie, 8);
669 727
670 info->next = od->icq_info; 728 od->icq_info = g_slist_prepend(od->icq_info, info);
671 od->icq_info = info;
672 729
673 flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs, FALSE); 730 flap_connection_send_snac_with_priority(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs, FALSE);
674 731
675 byte_stream_destroy(&bs); 732 byte_stream_destroy(&bs);
676 } 733 }
686 oscar_user_info_display_icq(od, info); 743 oscar_user_info_display_icq(od, info);
687 744
688 if (info->uin && info->nick) 745 if (info->uin && info->nick)
689 gotalias(od, info); 746 gotalias(od, info);
690 747
691 if (od->icq_info == info) {
692 od->icq_info = info->next;
693 } else {
694 struct aim_icq_info *cur;
695 for (cur=od->icq_info; (cur->next && (cur->next!=info)); cur=cur->next);
696 if (cur->next)
697 cur->next = cur->next->next;
698 }
699 aim_icq_freeinfo(info); 748 aim_icq_freeinfo(info);
749 od->icq_info = g_slist_remove(od->icq_info, info);
700 } 750 }
701 } 751 }
702 752
703 aim_tlvlist_free(tlvlist); 753 aim_tlvlist_free(tlvlist);
704 754
705 return ret; 755 return 1;
706 } 756 }
707 757
708 static int 758 static int
709 snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs) 759 snachandler(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
710 { 760 {
711 if (snac->subtype == 0x0003) 761 if (snac->subtype == 0x0001)
712 return icqresponse(od, conn, mod, frame, snac, bs); 762 return error(od, snac, bs);
763 else if (snac->subtype == 0x0003)
764 return icqresponse(od, snac, bs);
713 765
714 return 0; 766 return 0;
715 } 767 }
716 768
717 static void 769 static void
718 icq_shutdown(OscarData *od, aim_module_t *mod) 770 icq_shutdown(OscarData *od, aim_module_t *mod)
719 { 771 {
720 struct aim_icq_info *del; 772 GSList *cur;
721 773 for (cur = od->icq_info; cur; cur = cur->next)
722 while (od->icq_info) { 774 aim_icq_freeinfo(cur->data);
723 del = od->icq_info; 775 g_slist_free(od->icq_info);
724 od->icq_info = od->icq_info->next;
725 aim_icq_freeinfo(del);
726 }
727
728 return;
729 } 776 }
730 777
731 int 778 int
732 icq_modfirst(OscarData *od, aim_module_t *mod) 779 icq_modfirst(OscarData *od, aim_module_t *mod)
733 { 780 {