Merged pidgin/main into default
[pidgin-git.git] / libpurple / protocols / facebook / util.c
blob72890a5ad704acbace1753ca08d621e5fe8833c4
1 /* purple
3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * source distribution.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
22 #include "internal.h"
24 #include <gio/gio.h>
25 #include <stdarg.h>
26 #include <string.h>
28 #include "buddylist.h"
29 #include "conversations.h"
30 #include "glibcompat.h"
31 #include "message.h"
32 #include "request.h"
33 #include "server.h"
35 #include "util.h"
37 GQuark
38 fb_util_error_quark(void)
40 static GQuark q = 0;
42 if (G_UNLIKELY(q == 0)) {
43 q = g_quark_from_static_string("fb-util-error-quark");
46 return q;
49 PurpleBuddy *
50 fb_util_account_find_buddy(PurpleAccount *acct, PurpleChatConversation *chat,
51 const gchar *search, GError **error)
53 const gchar *alias;
54 const gchar *name;
55 GSList *buddies;
56 GSList *l;
57 guint retc;
58 PurpleBuddy *ret = NULL;
60 g_return_val_if_fail(PURPLE_IS_ACCOUNT(acct), NULL);
61 g_return_val_if_fail(search != NULL, NULL);
63 buddies = purple_blist_find_buddies(acct, NULL);
65 for (retc = 0, l = buddies; l != NULL; l = l->next) {
66 name = purple_buddy_get_name(l->data);
67 alias = purple_buddy_get_alias(l->data);
69 if ((chat != NULL) &&
70 !purple_chat_conversation_has_user(chat, name))
72 continue;
75 if (g_ascii_strcasecmp(name, search) == 0) {
76 ret = l->data;
77 retc++;
80 if (g_ascii_strcasecmp(alias, search) == 0) {
81 ret = l->data;
82 retc++;
86 if (retc == 0) {
87 g_set_error(error, FB_UTIL_ERROR, FB_UTIL_ERROR_GENERAL,
88 _("Buddy %s not found"), search);
89 } else if (retc > 1) {
90 g_set_error(error, FB_UTIL_ERROR, FB_UTIL_ERROR_GENERAL,
91 _("Buddy name %s is ambiguous"), search);
92 ret = NULL;
95 g_slist_free(buddies);
96 return ret;
99 void
100 fb_util_debug(PurpleDebugLevel level, const gchar *format, ...)
102 va_list ap;
104 va_start(ap, format);
105 fb_util_vdebug(level, format, ap);
106 va_end(ap);
109 void
110 fb_util_vdebug(PurpleDebugLevel level, const gchar *format, va_list ap)
112 gboolean unsafe;
113 gboolean verbose;
114 gchar *str;
116 g_return_if_fail(format != NULL);
118 unsafe = (level & FB_UTIL_DEBUG_FLAG_UNSAFE) != 0;
119 verbose = (level & FB_UTIL_DEBUG_FLAG_VERBOSE) != 0;
121 if ((unsafe && !purple_debug_is_unsafe()) ||
122 (verbose && !purple_debug_is_verbose()))
124 return;
127 /* Ensure all local flags are removed */
128 level &= ~FB_UTIL_DEBUG_FLAG_ALL;
130 str = g_strdup_vprintf(format, ap);
131 purple_debug(level, "facebook", "%s\n", str);
132 g_free(str);
135 void
136 fb_util_debug_misc(const gchar *format, ...)
138 va_list ap;
140 va_start(ap, format);
141 fb_util_vdebug(PURPLE_DEBUG_MISC, format, ap);
142 va_end(ap);
145 void
146 fb_util_debug_info(const gchar *format, ...)
148 va_list ap;
150 va_start(ap, format);
151 fb_util_vdebug(PURPLE_DEBUG_INFO, format, ap);
152 va_end(ap);
155 void
156 fb_util_debug_warning(const gchar *format, ...)
158 va_list ap;
160 va_start(ap, format);
161 fb_util_vdebug(PURPLE_DEBUG_WARNING, format, ap);
162 va_end(ap);
165 void
166 fb_util_debug_error(const gchar *format, ...)
168 va_list ap;
170 va_start(ap, format);
171 fb_util_vdebug(PURPLE_DEBUG_ERROR, format, ap);
172 va_end(ap);
175 void
176 fb_util_debug_fatal(const gchar *format, ...)
178 va_list ap;
180 va_start(ap, format);
181 fb_util_vdebug(PURPLE_DEBUG_FATAL, format, ap);
182 va_end(ap);
185 void
186 fb_util_debug_hexdump(PurpleDebugLevel level, const GByteArray *bytes,
187 const gchar *format, ...)
189 gchar c;
190 guint i;
191 guint j;
192 GString *gstr;
193 va_list ap;
195 static const gchar *indent = " ";
197 g_return_if_fail(bytes != NULL);
199 if (format != NULL) {
200 va_start(ap, format);
201 fb_util_vdebug(level, format, ap);
202 va_end(ap);
205 gstr = g_string_sized_new(80);
207 for (i = 0; i < bytes->len; i += 16) {
208 g_string_append_printf(gstr, "%s%08x ", indent, i);
210 for (j = 0; j < 16; j++) {
211 if ((i + j) < bytes->len) {
212 g_string_append_printf(gstr, "%02x ",
213 bytes->data[i + j]);
214 } else {
215 g_string_append(gstr, " ");
218 if (j == 7) {
219 g_string_append_c(gstr, ' ');
223 g_string_append(gstr, " |");
225 for (j = 0; (j < 16) && ((i + j) < bytes->len); j++) {
226 c = bytes->data[i + j];
228 if (!g_ascii_isprint(c) || g_ascii_isspace(c)) {
229 c = '.';
232 g_string_append_c(gstr, c);
235 g_string_append_c(gstr, '|');
236 fb_util_debug(level, "%s", gstr->str);
237 g_string_erase(gstr, 0, -1);
240 g_string_append_printf(gstr, "%s%08x", indent, i);
241 fb_util_debug(level, "%s", gstr->str);
242 g_string_free(gstr, TRUE);
245 gchar *
246 fb_util_get_locale(void)
248 const gchar * const *langs;
249 const gchar *lang;
250 gchar *chr;
251 guint i;
253 static const gchar chrs[] = {'.', '@'};
255 langs = g_get_language_names();
256 lang = langs[0];
258 if (purple_strequal(lang, "C")) {
259 return g_strdup("en_US");
262 for (i = 0; i < G_N_ELEMENTS(chrs); i++) {
263 chr = strchr(lang, chrs[i]);
265 if (chr != NULL) {
266 return g_strndup(lang, chr - lang);
270 return g_strdup(lang);
273 gchar *
274 fb_util_rand_alnum(guint len)
276 gchar *ret;
277 GRand *rand;
278 guint i;
279 guint j;
281 static const gchar chars[] =
282 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
283 "abcdefghijklmnopqrstuvwxyz"
284 "0123456789";
285 static const gsize charc = G_N_ELEMENTS(chars) - 1;
287 g_return_val_if_fail(len > 0, NULL);
288 rand = g_rand_new();
289 ret = g_new(gchar, len + 1);
291 for (i = 0; i < len; i++) {
292 j = g_rand_int_range(rand, 0, charc);
293 ret[i] = chars[j];
296 ret[len] = 0;
297 g_rand_free(rand);
298 return ret;
301 static void
302 fb_util_request_buddy_ok(gpointer *mata, PurpleRequestFields *fields)
304 FbUtilRequestBuddyFunc func = mata[0];
305 GList *l;
306 GList *select;
307 gpointer data = mata[2];
308 GSList *ret = NULL;
309 PurpleBuddy *bdy;
310 PurpleRequestField *field;
312 if (func == NULL) {
313 g_free(mata);
314 return;
317 field = purple_request_fields_get_field(fields, "buddy");
318 select = purple_request_field_list_get_selected(field);
320 for (l = select; l != NULL; l = l->next) {
321 bdy = purple_request_field_list_get_data(field, l->data);
322 ret = g_slist_prepend(ret, bdy);
325 ret = g_slist_reverse(ret);
326 func(ret, data);
328 g_slist_free(ret);
329 g_free(mata);
332 static void
333 fb_util_request_buddy_cancel(gpointer *mata, PurpleRequestFields *fields)
335 FbUtilRequestBuddyFunc func = mata[1];
336 gpointer data = mata[2];
338 if (func != NULL) {
339 func(NULL, data);
342 g_free(mata);
345 gpointer
346 fb_util_request_buddy(PurpleConnection *gc, const gchar *title,
347 const gchar *primary, const gchar *secondary,
348 GSList *select, gboolean multi, GCallback ok_cb,
349 GCallback cancel_cb, gpointer data)
351 const gchar *alias;
352 const gchar *name;
353 gchar *str;
354 GList *items = NULL;
355 gpointer *mata;
356 GSList *buddies;
357 GSList *l;
358 PurpleAccount *acct;
359 PurpleRequestCommonParameters *cpar;
360 PurpleRequestField *field;
361 PurpleRequestFieldGroup *group;
362 PurpleRequestFields *fields;
364 mata = g_new0(gpointer, 3);
365 mata[0] = ok_cb;
366 mata[1] = cancel_cb;
367 mata[2] = data;
369 acct = purple_connection_get_account(gc);
370 buddies = purple_blist_find_buddies(acct, NULL);
371 buddies = g_slist_sort(buddies, (GCompareFunc) g_ascii_strcasecmp);
373 fields = purple_request_fields_new();
374 group = purple_request_field_group_new(NULL);
375 purple_request_fields_add_group(fields, group);
377 field = purple_request_field_list_new("buddy", NULL);
378 purple_request_field_list_set_multi_select(field, multi);
379 purple_request_field_set_required(field, TRUE);
380 purple_request_field_group_add_field(group, field);
382 for (l = buddies; l != NULL; l = l->next) {
383 name = purple_buddy_get_name(l->data);
384 alias = purple_buddy_get_alias(l->data);
385 str = g_strdup_printf("%s (%s)", alias, name);
386 purple_request_field_list_add_icon(field, str, NULL, l->data);
387 g_free(str);
390 for (l = select; l != NULL; l = l->next) {
391 name = purple_buddy_get_name(l->data);
392 alias = purple_buddy_get_alias(l->data);
393 str = g_strdup_printf("%s (%s)", alias, name);
394 items = g_list_append(items, str);
397 purple_request_field_list_set_selected(field, items);
398 g_slist_free(buddies);
399 g_list_free_full(items, g_free);
401 cpar = purple_request_cpar_from_connection(gc);
402 return purple_request_fields(gc, title, primary, secondary, fields,
403 _("Ok"),
404 G_CALLBACK(fb_util_request_buddy_ok),
405 _("Cancel"),
406 G_CALLBACK(fb_util_request_buddy_cancel),
407 cpar, mata);
410 void
411 fb_util_serv_got_im(PurpleConnection *gc, const gchar *who, const gchar *text,
412 PurpleMessageFlags flags, guint64 timestamp)
414 const gchar *name;
415 PurpleAccount *acct;
416 PurpleIMConversation *conv;
417 PurpleMessage *msg;
419 if (!(flags & PURPLE_MESSAGE_SEND)) {
420 purple_serv_got_im(gc, who, text, flags, timestamp);
421 return;
424 acct = purple_connection_get_account(gc);
425 conv = purple_conversations_find_im_with_account(who, acct);
427 if (conv == NULL) {
428 conv = purple_im_conversation_new(acct, who);
431 name = purple_account_get_username(acct);
432 msg = purple_message_new_outgoing(name, text, flags);
433 purple_message_set_time(msg, timestamp);
434 purple_conversation_write_message(PURPLE_CONVERSATION(conv), msg);
437 void
438 fb_util_serv_got_chat_in(PurpleConnection *gc, gint id, const gchar *who,
439 const gchar *text, PurpleMessageFlags flags,
440 guint64 timestamp)
442 const gchar *name;
443 PurpleAccount *acct;
444 PurpleChatConversation *conv;
445 PurpleMessage *msg;
447 if (!(flags & PURPLE_MESSAGE_SEND)) {
448 purple_serv_got_chat_in(gc, id, who, flags, text, timestamp);
449 return;
452 acct = purple_connection_get_account(gc);
453 conv = purple_conversations_find_chat(gc, id);
455 name = purple_account_get_username(acct);
456 msg = purple_message_new_outgoing(name, text, flags);
457 purple_message_set_time(msg, timestamp);
458 purple_conversation_write_message(PURPLE_CONVERSATION(conv), msg);
461 gboolean
462 fb_util_strtest(const gchar *str, GAsciiType type)
464 gsize i;
465 gsize size;
466 guchar c;
468 g_return_val_if_fail(str != NULL, FALSE);
469 size = strlen(str);
471 for (i = 0; i < size; i++) {
472 c = (guchar) str[i];
474 if ((g_ascii_table[c] & type) == 0) {
475 return FALSE;
479 return TRUE;
482 gboolean
483 fb_util_zlib_test(const GByteArray *bytes)
485 guint8 b0;
486 guint8 b1;
488 g_return_val_if_fail(bytes != NULL, FALSE);
490 if (bytes->len < 2) {
491 return FALSE;
494 b0 = *(bytes->data + 0);
495 b1 = *(bytes->data + 1);
497 return ((((b0 << 8) | b1) % 31) == 0) && /* Check the header */
498 ((b0 & 0x0F) == 8 /* Z_DEFLATED */); /* Check the method */
501 static GByteArray *
502 fb_util_zlib_conv(GConverter *conv, const GByteArray *bytes, GError **error)
504 GByteArray *ret;
505 GConverterResult res;
506 gsize cize = 0;
507 gsize rize;
508 gsize wize;
509 guint8 data[1024];
511 ret = g_byte_array_new();
513 while (TRUE) {
514 rize = 0;
515 wize = 0;
517 res = g_converter_convert(conv,
518 bytes->data + cize,
519 bytes->len - cize,
520 data, sizeof data,
521 G_CONVERTER_INPUT_AT_END,
522 &rize, &wize, error);
524 switch (res) {
525 case G_CONVERTER_CONVERTED:
526 g_byte_array_append(ret, data, wize);
527 cize += rize;
528 break;
530 case G_CONVERTER_ERROR:
531 g_byte_array_free(ret, TRUE);
532 return NULL;
534 case G_CONVERTER_FINISHED:
535 g_byte_array_append(ret, data, wize);
536 return ret;
538 default:
539 break;
544 GByteArray *
545 fb_util_zlib_deflate(const GByteArray *bytes, GError **error)
547 GByteArray *ret;
548 GZlibCompressor *conv;
550 conv = g_zlib_compressor_new(G_ZLIB_COMPRESSOR_FORMAT_ZLIB, -1);
551 ret = fb_util_zlib_conv(G_CONVERTER(conv), bytes, error);
552 g_object_unref(conv);
553 return ret;
556 GByteArray *
557 fb_util_zlib_inflate(const GByteArray *bytes, GError **error)
559 GByteArray *ret;
560 GZlibDecompressor *conv;
562 conv = g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_ZLIB);
563 ret = fb_util_zlib_conv(G_CONVERTER(conv), bytes, error);
564 g_object_unref(conv);
565 return ret;