Mercurial > pidgin
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 { |