comparison src/protocols/oscar/oscar.c @ 5129:c19cc54f4df6

[gaim-migrate @ 5492] Stuff I did (in order from most important to least): -Made set away message and set profile count the number of bytes rather than the number of characters. This fixes the lack of a warning dialog when setting info that needs an encoding other than ascii or iso8859-1. (Because "hi" in UCS-2BE is 4 bytes but "hi" in utf8 is only 2.) -Created an oscar_encoding_to_utf8 function to convert from a given encoding to utf8. This is AIM/ICQ specific. -Added a "Profile:" and "Away Message:" line to the get info response window. Is it better this way or without it? I thought it would be good if there was a way for users to tell which text was the away message and which was the info, but I also think this solution could be nicer looking. -Added a little check for some server icon stuff because someone reported an obscure crash. -Shuffled some stuff around in oscar.c -Bouldered on the little wall outside of the gym today. It's much more difficult than climbing inside. I think my forearms are just a bit too weak. The holds are tiny, though. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Mon, 14 Apr 2003 04:52:42 +0000
parents 74139d2562f5
children feda37d46e17
comparison
equal deleted inserted replaced
5128:29a834316b34 5129:c19cc54f4df6
197 struct gaim_connection *gc; 197 struct gaim_connection *gc;
198 gchar *name; 198 gchar *name;
199 gchar *nick; 199 gchar *nick;
200 }; 200 };
201 201
202 static void gaim_free_name_data(struct name_data *data) { 202 static char *msgerrreason[] = {
203 g_free(data->name); 203 N_("Invalid error"),
204 g_free(data->nick); 204 N_("Invalid SNAC"),
205 g_free(data); 205 N_("Rate to host"),
206 } 206 N_("Rate to client"),
207 207 N_("Not logged in"),
208 static struct direct_im *find_direct_im(struct oscar_data *od, const char *who) { 208 N_("Service unavailable"),
209 GSList *d = od->direct_ims; 209 N_("Service not defined"),
210 struct direct_im *m = NULL; 210 N_("Obsolete SNAC"),
211 211 N_("Not supported by host"),
212 while (d) { 212 N_("Not supported by client"),
213 m = (struct direct_im *)d->data; 213 N_("Refused by client"),
214 if (!aim_sncmp(who, m->name)) 214 N_("Reply too big"),
215 return m; 215 N_("Responses lost"),
216 d = d->next; 216 N_("Request denied"),
217 } 217 N_("Busted SNAC payload"),
218 218 N_("Insufficient rights"),
219 return NULL; 219 N_("In local permit/deny"),
220 } 220 N_("Too evil (sender)"),
221 221 N_("Too evil (receiver)"),
222 static char *extract_name(const char *name) { 222 N_("User temporarily unavailable"),
223 char *tmp, *x; 223 N_("No match"),
224 int i, j; 224 N_("List overflow"),
225 225 N_("Request ambiguous"),
226 if (!name) 226 N_("Queue full"),
227 return NULL; 227 N_("Not while on AOL")
228 228 };
229 x = strchr(name, '-'); 229 static int msgerrreasonlen = 25;
230
231 if (!x) return NULL;
232 x = strchr(++x, '-');
233 if (!x) return NULL;
234 tmp = g_strdup(++x);
235
236 for (i = 0, j = 0; x[i]; i++) {
237 char hex[3];
238 if (x[i] != '%') {
239 tmp[j++] = x[i];
240 continue;
241 }
242 strncpy(hex, x + ++i, 2); hex[2] = 0;
243 i++;
244 tmp[j++] = strtol(hex, NULL, 16);
245 }
246
247 tmp[j] = 0;
248 return tmp;
249 }
250
251 static struct chat_connection *find_oscar_chat(struct gaim_connection *gc, int id) {
252 GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats;
253 struct chat_connection *c = NULL;
254
255 while (g) {
256 c = (struct chat_connection *)g->data;
257 if (c->id == id)
258 break;
259 g = g->next;
260 c = NULL;
261 }
262
263 return c;
264 }
265
266 static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc,
267 aim_conn_t *conn) {
268 GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats;
269 struct chat_connection *c = NULL;
270
271 while (g) {
272 c = (struct chat_connection *)g->data;
273 if (c->conn == conn)
274 break;
275 g = g->next;
276 c = NULL;
277 }
278
279 return c;
280 }
281 230
282 /* All the libfaim->gaim callback functions */ 231 /* All the libfaim->gaim callback functions */
283 static int gaim_parse_auth_resp (aim_session_t *, aim_frame_t *, ...); 232 static int gaim_parse_auth_resp (aim_session_t *, aim_frame_t *, ...);
284 static int gaim_parse_login (aim_session_t *, aim_frame_t *, ...); 233 static int gaim_parse_login (aim_session_t *, aim_frame_t *, ...);
285 static int gaim_handle_redirect (aim_session_t *, aim_frame_t *, ...); 234 static int gaim_handle_redirect (aim_session_t *, aim_frame_t *, ...);
351 static int oscar_sendfile_done (aim_session_t *, aim_frame_t *, ...); 300 static int oscar_sendfile_done (aim_session_t *, aim_frame_t *, ...);
352 301
353 /* for icons */ 302 /* for icons */
354 static gboolean gaim_icon_timerfunc(gpointer data); 303 static gboolean gaim_icon_timerfunc(gpointer data);
355 304
356 static fu32_t check_encoding(const char *utf8); 305 static void gaim_free_name_data(struct name_data *data) {
357 static fu32_t parse_encoding(const char *enc); 306 g_free(data->name);
358 307 g_free(data->nick);
359 static char *msgerrreason[] = { 308 g_free(data);
360 N_("Invalid error"), 309 }
361 N_("Invalid SNAC"), 310
362 N_("Rate to host"), 311 static fu32_t oscar_encoding_check(const char *utf8)
363 N_("Rate to client"), 312 {
364 N_("Not logged in"), 313 int i = 0;
365 N_("Service unavailable"), 314 fu32_t encodingflag = 0;
366 N_("Service not defined"), 315
367 N_("Obsolete SNAC"), 316 /* Determine how we can send this message. Per the warnings elsewhere
368 N_("Not supported by host"), 317 * in this file, these little checks determine the simplest encoding
369 N_("Not supported by client"), 318 * we can use for a given message send using it. */
370 N_("Refused by client"), 319 while (utf8[i]) {
371 N_("Reply too big"), 320 if ((unsigned char)utf8[i] > 0x7f) {
372 N_("Responses lost"), 321 /* not ASCII! */
373 N_("Request denied"), 322 encodingflag = AIM_IMFLAGS_ISO_8859_1;
374 N_("Busted SNAC payload"), 323 break;
375 N_("Insufficient rights"), 324 }
376 N_("In local permit/deny"), 325 i++;
377 N_("Too evil (sender)"), 326 }
378 N_("Too evil (receiver)"), 327 while (utf8[i]) {
379 N_("User temporarily unavailable"), 328 /* ISO-8859-1 is 0x00-0xbf in the first byte
380 N_("No match"), 329 * followed by 0xc0-0xc3 in the second */
381 N_("List overflow"), 330 if ((unsigned char)utf8[i] < 0x80) {
382 N_("Request ambiguous"), 331 i++;
383 N_("Queue full"), 332 continue;
384 N_("Not while on AOL") 333 } else if (((unsigned char)utf8[i] & 0xfc) == 0xc0 &&
385 }; 334 ((unsigned char)utf8[i + 1] & 0xc0) == 0x80) {
386 static int msgerrreasonlen = 25; 335 i += 2;
336 continue;
337 }
338 encodingflag = AIM_IMFLAGS_UNICODE;
339 break;
340 }
341
342 return encodingflag;
343 }
344
345 static fu32_t oscar_encoding_parse(const char *enc)
346 {
347 char *charset;
348
349 /* If anything goes wrong, fall back on ASCII and print a message */
350 if (enc == NULL) {
351 debug_printf("Encoding was null, that's odd\n");
352 return 0;
353 }
354 charset = strstr(enc, "charset=");
355 if (charset == NULL) {
356 debug_printf("No charset specified for info, assuming ASCII\n");
357 return 0;
358 }
359 charset += 8;
360 if (!strcmp(charset, "\"us-ascii\"") || !strcmp(charset, "\"utf-8\"")) {
361 /* UTF-8 is our native charset, ASCII is a proper subset */
362 return 0;
363 } else if (!strcmp(charset, "\"iso-8859-1\"")) {
364 return AIM_IMFLAGS_ISO_8859_1;
365 } else if (!strcmp(charset, "\"unicode-2-0\"")) {
366 return AIM_IMFLAGS_UNICODE;
367 } else {
368 debug_printf("Unrecognized character set '%s', using ASCII\n", charset);
369 return 0;
370 }
371 }
372
373 gchar *oscar_encoding_to_utf8(const char *encoding, char *text, int textlen)
374 {
375 gchar *utf8 = NULL;
376 int flags = oscar_encoding_parse(encoding);
377
378 switch (flags) {
379 case 0:
380 utf8 = g_strndup(text, textlen);
381 break;
382 case AIM_IMFLAGS_ISO_8859_1:
383 utf8 = g_convert(text, textlen, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
384 break;
385 case AIM_IMFLAGS_UNICODE:
386 utf8 = g_convert(text, textlen, "UTF-8", "UCS-2BE", NULL, NULL, NULL);
387 break;
388 }
389
390 return utf8;
391 }
392
393 static struct direct_im *find_direct_im(struct oscar_data *od, const char *who) {
394 GSList *d = od->direct_ims;
395 struct direct_im *m = NULL;
396
397 while (d) {
398 m = (struct direct_im *)d->data;
399 if (!aim_sncmp(who, m->name))
400 return m;
401 d = d->next;
402 }
403
404 return NULL;
405 }
406
407 static char *extract_name(const char *name) {
408 char *tmp, *x;
409 int i, j;
410
411 if (!name)
412 return NULL;
413
414 x = strchr(name, '-');
415
416 if (!x) return NULL;
417 x = strchr(++x, '-');
418 if (!x) return NULL;
419 tmp = g_strdup(++x);
420
421 for (i = 0, j = 0; x[i]; i++) {
422 char hex[3];
423 if (x[i] != '%') {
424 tmp[j++] = x[i];
425 continue;
426 }
427 strncpy(hex, x + ++i, 2); hex[2] = 0;
428 i++;
429 tmp[j++] = strtol(hex, NULL, 16);
430 }
431
432 tmp[j] = 0;
433 return tmp;
434 }
435
436 static struct chat_connection *find_oscar_chat(struct gaim_connection *gc, int id) {
437 GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats;
438 struct chat_connection *c = NULL;
439
440 while (g) {
441 c = (struct chat_connection *)g->data;
442 if (c->id == id)
443 break;
444 g = g->next;
445 c = NULL;
446 }
447
448 return c;
449 }
450
451 static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc,
452 aim_conn_t *conn) {
453 GSList *g = ((struct oscar_data *)gc->proto_data)->oscar_chats;
454 struct chat_connection *c = NULL;
455
456 while (g) {
457 c = (struct chat_connection *)g->data;
458 if (c->conn == conn)
459 break;
460 g = g->next;
461 c = NULL;
462 }
463
464 return c;
465 }
387 466
388 static void gaim_odc_disconnect(aim_session_t *sess, aim_conn_t *conn) { 467 static void gaim_odc_disconnect(aim_session_t *sess, aim_conn_t *conn) {
389 struct gaim_connection *gc = sess->aux_data; 468 struct gaim_connection *gc = sess->aux_data;
390 struct oscar_data *od = (struct oscar_data *)gc->proto_data; 469 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
391 struct gaim_conversation *cnv; 470 struct gaim_conversation *cnv;
3044 struct oscar_data *od = gc->proto_data; 3123 struct oscar_data *od = gc->proto_data;
3045 char header[BUF_LONG]; 3124 char header[BUF_LONG];
3046 GSList *l = od->evilhack; 3125 GSList *l = od->evilhack;
3047 gboolean evilhack = FALSE; 3126 gboolean evilhack = FALSE;
3048 gchar *membersince = NULL, *onlinesince = NULL, *idle = NULL; 3127 gchar *membersince = NULL, *onlinesince = NULL, *idle = NULL;
3049 fu32_t flags;
3050 va_list ap; 3128 va_list ap;
3051 aim_userinfo_t *info; 3129 aim_userinfo_t *info;
3052 fu16_t infotype; 3130 fu16_t infotype;
3053 char *text_enc = NULL, *text = NULL, *utf8 = NULL; 3131 char *text_enc = NULL, *text = NULL, *utf8 = NULL;
3054 int text_len; 3132 int text_len;
3060 text = va_arg(ap, char *); 3138 text = va_arg(ap, char *);
3061 text_len = va_arg(ap, int); 3139 text_len = va_arg(ap, int);
3062 va_end(ap); 3140 va_end(ap);
3063 3141
3064 if (text_len > 0) { 3142 if (text_len > 0) {
3065 flags = parse_encoding (text_enc); 3143 if (!(utf8 = oscar_encoding_to_utf8(text_enc, text, text_len))) {
3066 switch (flags) {
3067 case 0:
3068 utf8 = g_strndup(text, text_len);
3069 break;
3070 case AIM_IMFLAGS_ISO_8859_1:
3071 utf8 = g_convert(text, text_len, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
3072 break;
3073 case AIM_IMFLAGS_UNICODE:
3074 utf8 = g_convert(text, text_len, "UTF-8", "UCS-2BE", NULL, NULL, NULL);
3075 break;
3076 default:
3077 utf8 = g_strdup(_("<i>Unable to display information because it was sent in an unknown encoding.</i>")); 3144 utf8 = g_strdup(_("<i>Unable to display information because it was sent in an unknown encoding.</i>"));
3078 debug_printf("Encountered an unknown encoding while parsing userinfo\n"); 3145 debug_printf("Encountered an unknown encoding while parsing userinfo\n");
3079 } 3146 }
3080 } 3147 }
3081 3148
3131 (utf8 && *utf8) ? away_subs(utf8, gc->username) : 3198 (utf8 && *utf8) ? away_subs(utf8, gc->username) :
3132 _("<i>User has no away message</i>"), NULL); 3199 _("<i>User has no away message</i>"), NULL);
3133 } else { 3200 } else {
3134 g_show_info_text(gc, info->sn, 0, 3201 g_show_info_text(gc, info->sn, 0,
3135 header, 3202 header,
3203 (utf8 && *utf8) ? _("<b>Away Message:</b><br>") : NULL,
3136 (utf8 && *utf8) ? away_subs(utf8, gc->username) : NULL, 3204 (utf8 && *utf8) ? away_subs(utf8, gc->username) : NULL,
3137 (utf8 && *utf8) ? "<hr>" : NULL, 3205 (utf8 && *utf8) ? "<hr>" : NULL,
3138 NULL); 3206 NULL);
3139 } 3207 }
3140 } else if (infotype == AIM_GETINFO_CAPABILITIES) { 3208 } else if (infotype == AIM_GETINFO_CAPABILITIES) {
3144 caps_string(info->capabilities), 3212 caps_string(info->capabilities),
3145 "</i>", 3213 "</i>",
3146 NULL); 3214 NULL);
3147 } else { 3215 } else {
3148 g_show_info_text(gc, info->sn, 1, 3216 g_show_info_text(gc, info->sn, 1,
3149 (utf8 && *utf8) ? away_subs(utf8, gc->username) : 3217 (utf8 && *utf8) ? _("<b>Profile:</b><br>") : _("<i>No Information Provided</i>"),
3150 _("<i>No Information Provided</i>"), 3218 (utf8 && *utf8) ? away_subs(utf8, gc->username) : NULL,
3151 NULL); 3219 NULL);
3152 } 3220 }
3153 3221
3154 g_free(utf8); 3222 g_free(utf8);
3155 3223
3398 iconlen = va_arg(ap, int); 3466 iconlen = va_arg(ap, int);
3399 va_end(ap); 3467 va_end(ap);
3400 3468
3401 if (iconlen > 0) { 3469 if (iconlen > 0) {
3402 char *b16; 3470 char *b16;
3403 struct buddy *b; 3471 struct buddy *b = gaim_find_buddy(gc->account, sn);
3404 set_icon_data(gc, sn, icon, iconlen); 3472 set_icon_data(gc, sn, icon, iconlen);
3405 b16 = tobase16(iconcsum, iconcsumlen); 3473 b16 = tobase16(iconcsum, iconcsumlen);
3406 b = gaim_find_buddy(gc->account, sn); 3474 if (b16) {
3407 gaim_buddy_set_setting(b, "icon_checksum", b16); 3475 gaim_buddy_set_setting(b, "icon_checksum", b16);
3408 gaim_blist_save(); 3476 gaim_blist_save();
3409 if(b16)
3410 free(b16); 3477 free(b16);
3478 }
3411 } 3479 }
3412 3480
3413 cur = od->requesticon; 3481 cur = od->requesticon;
3414 while (cur) { 3482 while (cur) {
3415 char *cursn = cur->data; 3483 char *cursn = cur->data;
3697 od->rights.maxsiglen = od->rights.maxawaymsglen = (guint)maxsiglen; 3765 od->rights.maxsiglen = od->rights.maxawaymsglen = (guint)maxsiglen;
3698 3766
3699 if (od->icq) 3767 if (od->icq)
3700 aim_bos_setprofile(sess, fr->conn, NULL, NULL, 0, NULL, NULL, 0, caps_icq); 3768 aim_bos_setprofile(sess, fr->conn, NULL, NULL, 0, NULL, NULL, 0, caps_icq);
3701 else { 3769 else {
3702 flags = check_encoding (gc->account->user_info); 3770 flags = oscar_encoding_check (gc->account->user_info);
3703 3771
3704 if (flags == 0) { 3772 if (flags == 0) {
3705 aim_bos_setprofile(sess, fr->conn, "us-ascii", gc->account->user_info, 3773 aim_bos_setprofile(sess, fr->conn, "us-ascii", gc->account->user_info,
3706 strlen(gc->account->user_info), NULL, NULL, 0, caps_aim); 3774 strlen(gc->account->user_info), NULL, NULL, 0, caps_aim);
3707 } else { 3775 } else {
4195 } 4263 }
4196 4264
4197 args.destsn = name; 4265 args.destsn = name;
4198 4266
4199 len = strlen(message); 4267 len = strlen(message);
4200 args.flags |= check_encoding(message); 4268 args.flags |= oscar_encoding_check(message);
4201 if (args.flags & AIM_IMFLAGS_UNICODE) { 4269 if (args.flags & AIM_IMFLAGS_UNICODE) {
4202 debug_printf("Sending Unicode IM\n"); 4270 debug_printf("Sending Unicode IM\n");
4203 args.charset = 0x0002; 4271 args.charset = 0x0002;
4204 args.charsubset = 0x0000; 4272 args.charsubset = 0x0000;
4205 args.msg = g_convert(message, len, "UCS-2BE", "UTF-8", NULL, &len, &err); 4273 args.msg = g_convert(message, len, "UCS-2BE", "UTF-8", NULL, &len, &err);
4275 aim_setdirectoryinfo(od->sess, od->conn, first, middle, last, 4343 aim_setdirectoryinfo(od->sess, od->conn, first, middle, last,
4276 maiden, NULL, NULL, city, state, NULL, 0, web); 4344 maiden, NULL, NULL, city, state, NULL, 0, web);
4277 } 4345 }
4278 4346
4279 4347
4280 static void oscar_set_idle(struct gaim_connection *g, int time) { 4348 static void oscar_set_idle(struct gaim_connection *gc, int time) {
4281 struct oscar_data *od = (struct oscar_data *)g->proto_data; 4349 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
4282 aim_bos_setidle(od->sess, od->conn, time); 4350 aim_bos_setidle(od->sess, od->conn, time);
4283 } 4351 }
4284 4352
4285 static void oscar_set_info(struct gaim_connection *g, char *info) { 4353 static void oscar_set_info(struct gaim_connection *gc, char *text) {
4286 struct oscar_data *od = (struct oscar_data *)g->proto_data; 4354 struct oscar_data *od = (struct oscar_data *)gc->proto_data;
4287 gchar *inforeal, *unicode; 4355 fu32_t flags = 0;
4288 fu32_t flags; 4356 char *msg = NULL;
4289 int unicode_len; 4357 int msglen = 0;
4290 4358
4291 if (od->rights.maxsiglen == 0) 4359 if (od->rights.maxsiglen == 0)
4292 do_error_dialog(_("Unable to set AIM profile."), 4360 do_error_dialog(_("Unable to set AIM profile."),
4293 _("You have probably requested to set your profile before the login procedure completed. " 4361 _("You have probably requested to set your profile before the login procedure completed. "
4294 "Your profile remains unset; try setting it again when you are fully connected."), GAIM_ERROR); 4362 "Your profile remains unset; try setting it again when you are fully connected."), GAIM_WARNING);
4295
4296 if (strlen(info) > od->rights.maxsiglen) {
4297 gchar *errstr;
4298
4299 errstr = g_strdup_printf(_("The maximum profile length of %d bytes has been exceeded. "
4300 "Gaim has truncated and set it."), od->rights.maxsiglen);
4301 do_error_dialog("Profile too long.", errstr, GAIM_WARNING);
4302
4303 g_free(errstr);
4304 }
4305
4306 inforeal = g_strndup(info, od->rights.maxsiglen);
4307 4363
4308 if (od->icq) 4364 if (od->icq)
4309 aim_bos_setprofile(od->sess, od->conn, NULL, NULL, 0, NULL, NULL, 0, caps_icq); 4365 aim_bos_setprofile(od->sess, od->conn, NULL, NULL, 0, NULL, NULL, 0, caps_icq);
4310 else { 4366 else {
4311 flags = check_encoding(inforeal); 4367 if (!text) {
4312 4368 aim_bos_setprofile(od->sess, od->conn, NULL, NULL, 0, NULL, NULL, 0, caps_aim);
4313 if (flags == 0) { 4369 return;
4314 aim_bos_setprofile(od->sess, od->conn, "us-ascii", inforeal, strlen (inforeal), 4370 }
4315 NULL, NULL, 0, caps_aim); 4371
4372 flags = oscar_encoding_check(text);
4373 if (flags & AIM_IMFLAGS_UNICODE) {
4374 msg = g_convert(text, strlen(text), "UCS-2BE", "UTF-8", NULL, &msglen, NULL);
4375 aim_bos_setprofile(od->sess, od->conn, "unicode-2-0", msg, (msglen > od->rights.maxsiglen ? od->rights.maxsiglen : msglen), NULL, NULL, 0, caps_aim);
4376 g_free(msg);
4377 gc->away = g_strndup(text, od->rights.maxsiglen/2);
4378 } else if (flags & AIM_IMFLAGS_ISO_8859_1) {
4379 msg = g_convert(text, strlen(text), "ISO-8859-1", "UTF-8", NULL, &msglen, NULL);
4380 aim_bos_setprofile(od->sess, od->conn, "iso-8859-1", msg, (msglen > od->rights.maxsiglen ? od->rights.maxsiglen : msglen), NULL, NULL, 0, caps_aim);
4381 g_free(msg);
4382 gc->away = g_strndup(text, od->rights.maxsiglen);
4316 } else { 4383 } else {
4317 unicode = g_convert (inforeal, strlen(inforeal), "UCS-2BE", "UTF-8", NULL, 4384 msglen = strlen(text);
4318 &unicode_len, NULL); 4385 aim_bos_setprofile(od->sess, od->conn, "us-ascii", text, (msglen > od->rights.maxsiglen ? od->rights.maxsiglen : msglen), NULL, NULL, 0, caps_aim);
4319 aim_bos_setprofile(od->sess, od->conn, "unicode-2-0", unicode, unicode_len, 4386 gc->away = g_strndup(text, od->rights.maxsiglen);
4320 NULL, NULL, 0, caps_aim); 4387 }
4321 g_free(unicode); 4388
4322 } 4389 if (msglen > od->rights.maxsiglen) {
4323 } 4390 gchar *errstr;
4324 g_free(inforeal); 4391 errstr = g_strdup_printf(_("The maximum profile length of %d bytes has been exceeded. "
4392 "Gaim has truncated it for you."), od->rights.maxsiglen);
4393 do_error_dialog(_("Profile too long."), errstr, GAIM_WARNING);
4394 g_free(errstr);
4395 }
4396
4397 }
4325 4398
4326 return; 4399 return;
4327 } 4400 }
4328 4401
4329 static void oscar_set_away_aim(struct gaim_connection *gc, struct oscar_data *od, const char *message) 4402 static void oscar_set_away_aim(struct gaim_connection *gc, struct oscar_data *od, const char *text)
4330 { 4403 {
4331 fu32_t flags; 4404 fu32_t flags = 0;
4332 char *unicode; 4405 char *msg = NULL;
4333 int unicode_len; 4406 int msglen = 0;
4334 4407
4335 if (od->rights.maxawaymsglen == 0) 4408 if (od->rights.maxawaymsglen == 0)
4336 do_error_dialog(_("Unable to set AIM away message."), 4409 do_error_dialog(_("Unable to set AIM away message."),
4337 _("You have probably requested to set your away message before the login procedure completed. " 4410 _("You have probably requested to set your away message before the login procedure completed. "
4338 "You remain in a \"present\" state; try setting it again when you are fully connected."), GAIM_ERROR); 4411 "You remain in a \"present\" state; try setting it again when you are fully connected."), GAIM_WARNING);
4339 4412
4340 if (gc->away) { 4413 if (gc->away) {
4341 g_free(gc->away); 4414 g_free(gc->away);
4342 gc->away = NULL; 4415 gc->away = NULL;
4343 } 4416 }
4344 4417
4345 if (!message) { 4418 if (!text) {
4346 aim_bos_setprofile(od->sess, od->conn, NULL, NULL, 0, NULL, "", 0, caps_aim); 4419 aim_bos_setprofile(od->sess, od->conn, NULL, NULL, 0, NULL, "", 0, caps_aim);
4347 return; 4420 return;
4348 } 4421 }
4349 4422
4350 if (strlen(message) > od->rights.maxawaymsglen) { 4423 flags = oscar_encoding_check(text);
4424 if (flags & AIM_IMFLAGS_UNICODE) {
4425 msg = g_convert(text, strlen(text), "UCS-2BE", "UTF-8", NULL, &msglen, NULL);
4426 aim_bos_setprofile(od->sess, od->conn, NULL, NULL, 0, "unicode-2-0", msg,
4427 (msglen > od->rights.maxawaymsglen ? od->rights.maxawaymsglen : msglen), caps_aim);
4428 g_free(msg);
4429 gc->away = g_strndup(text, od->rights.maxawaymsglen/2);
4430 } else if (flags & AIM_IMFLAGS_ISO_8859_1) {
4431 msg = g_convert(text, strlen(text), "ISO-8859-1", "UTF-8", NULL, &msglen, NULL);
4432 aim_bos_setprofile(od->sess, od->conn, NULL, NULL, 0, "iso-8859-1", msg,
4433 (msglen > od->rights.maxawaymsglen ? od->rights.maxawaymsglen : msglen), caps_aim);
4434 g_free(msg);
4435 gc->away = g_strndup(text, od->rights.maxawaymsglen);
4436 } else {
4437 msglen = strlen(text);
4438 aim_bos_setprofile(od->sess, od->conn, NULL, NULL, 0, "us-ascii", text,
4439 (msglen > od->rights.maxawaymsglen ? od->rights.maxawaymsglen : msglen), caps_aim);
4440 gc->away = g_strndup(text, od->rights.maxawaymsglen);
4441 }
4442
4443 if (msglen > od->rights.maxawaymsglen) {
4351 gchar *errstr; 4444 gchar *errstr;
4352 4445
4353 errstr = g_strdup_printf(_("The away message length of %d bytes has been exceeded. " 4446 errstr = g_strdup_printf(_("The maximum away message length of %d bytes has been exceeded. "
4354 "Gaim has truncated it and set you away."), od->rights.maxawaymsglen); 4447 "Gaim has truncated it and set you away."), od->rights.maxawaymsglen);
4355 do_error_dialog("Away message too long.", errstr, GAIM_WARNING); 4448 do_error_dialog(_("Away message too long."), errstr, GAIM_WARNING);
4356 g_free(errstr); 4449 g_free(errstr);
4357 }
4358
4359 gc->away = g_strndup(message, od->rights.maxawaymsglen);
4360 flags = check_encoding(message);
4361
4362 if (flags == 0) {
4363 aim_bos_setprofile(od->sess, od->conn, NULL, NULL, 0, "us-ascii", gc->away, strlen(gc->away),
4364 caps_aim);
4365 } else {
4366 unicode = g_convert(message, strlen(message), "UCS-2BE", "UTF-8", NULL, &unicode_len, NULL);
4367 aim_bos_setprofile(od->sess, od->conn, NULL, NULL, 0, "unicode-2-0", unicode, unicode_len,
4368 caps_aim);
4369 g_free(unicode);
4370 } 4450 }
4371 4451
4372 return; 4452 return;
4373 } 4453 }
4374 4454
5777 5857
5778 od->direct_ims = g_slist_remove(od->direct_ims, dim); 5858 od->direct_ims = g_slist_remove(od->direct_ims, dim);
5779 gaim_input_remove(dim->watcher); 5859 gaim_input_remove(dim->watcher);
5780 aim_conn_kill(od->sess, &dim->conn); 5860 aim_conn_kill(od->sess, &dim->conn);
5781 g_free(dim); 5861 g_free(dim);
5782 }
5783
5784 static fu32_t check_encoding(const char *utf8)
5785 {
5786 int i = 0;
5787 fu32_t encodingflag = 0;
5788
5789 /* Determine how we can send this message. Per the
5790 * warnings elsewhere in this file, these little
5791 * checks determine the simplest encoding we can use
5792 * for a given message send using it. */
5793 while (utf8[i]) {
5794 if ((unsigned char)utf8[i] > 0x7f) {
5795 /* not ASCII! */
5796 encodingflag = AIM_IMFLAGS_ISO_8859_1;
5797 break;
5798 }
5799 i++;
5800 }
5801 while (utf8[i]) {
5802 /* ISO-8859-1 is 0x00-0xbf in the first byte
5803 * followed by 0xc0-0xc3 in the second */
5804 if ((unsigned char)utf8[i] < 0x80) {
5805 i++;
5806 continue;
5807 } else if (((unsigned char)utf8[i] & 0xfc) == 0xc0 &&
5808 ((unsigned char)utf8[i + 1] & 0xc0) == 0x80) {
5809 i += 2;
5810 continue;
5811 }
5812 encodingflag = AIM_IMFLAGS_UNICODE;
5813 break;
5814 }
5815
5816 return encodingflag;
5817 }
5818
5819 static fu32_t parse_encoding(const char *enc)
5820 {
5821 char *charset;
5822
5823 /* If anything goes wrong, fall back on ASCII and print a message */
5824 if (enc == NULL) {
5825 debug_printf("Encoding was null, that's odd\n");
5826 return 0;
5827 }
5828 charset = strstr(enc, "charset=");
5829 if (charset == NULL) {
5830 debug_printf("No charset specified for info, assuming ASCII\n");
5831 return 0;
5832 }
5833 charset += 8;
5834 if (!strcmp(charset, "\"us-ascii\"") || !strcmp(charset, "\"utf-8\"")) {
5835 /* UTF-8 is our native charset, ASCII is a proper subset */
5836 return 0;
5837 } else if (!strcmp(charset, "\"iso-8859-1\"")) {
5838 return AIM_IMFLAGS_ISO_8859_1;
5839 } else if (!strcmp(charset, "\"unicode-2-0\"")) {
5840 return AIM_IMFLAGS_UNICODE;
5841 } else {
5842 debug_printf("Unrecognized character set '%s', using ASCII\n", charset);
5843 return 0;
5844 }
5845 } 5862 }
5846 5863
5847 G_MODULE_EXPORT void oscar_init(struct prpl *ret) { 5864 G_MODULE_EXPORT void oscar_init(struct prpl *ret) {
5848 struct proto_user_opt *puo; 5865 struct proto_user_opt *puo;
5849 ret->protocol = PROTO_OSCAR; 5866 ret->protocol = PROTO_OSCAR;