Replace functions which called once with their bodies
[pidgin-git.git] / libpurple / protocols / facebook / util.c
blobe87acf5edaa970d382957e521a4b76f199ee0ed8
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 static gint
346 fb_buddy_cmp(gconstpointer a, gconstpointer b)
348 PurpleBuddy *pba, *pbb;
349 gint alias_verdict, name_verdict;
350 gchar *astr, *bstr;
352 pba = PURPLE_BUDDY(a);
353 pbb = PURPLE_BUDDY(b);
355 astr = g_utf8_casefold(purple_buddy_get_alias(pba), -1);
356 bstr = g_utf8_casefold(purple_buddy_get_alias(pbb), -1);
357 alias_verdict = g_utf8_collate(astr, bstr);
358 g_free(astr);
359 g_free(bstr);
360 if (alias_verdict != 0) {
361 return alias_verdict;
363 astr = g_utf8_casefold(purple_buddy_get_name(pba), -1);
364 bstr = g_utf8_casefold(purple_buddy_get_name(pbb), -1);
365 name_verdict = g_utf8_collate(astr, bstr);
366 g_free(astr);
367 g_free(bstr);
368 return name_verdict;
371 gpointer
372 fb_util_request_buddy(PurpleConnection *gc, const gchar *title,
373 const gchar *primary, const gchar *secondary,
374 GSList *select, gboolean multi, GCallback ok_cb,
375 GCallback cancel_cb, gpointer data)
377 const gchar *alias;
378 const gchar *name;
379 gchar *str;
380 GList *items = NULL;
381 gpointer *mata;
382 GSList *buddies;
383 GSList *l;
384 PurpleAccount *acct;
385 PurpleRequestCommonParameters *cpar;
386 PurpleRequestField *field;
387 PurpleRequestFieldGroup *group;
388 PurpleRequestFields *fields;
390 mata = g_new0(gpointer, 3);
391 mata[0] = ok_cb;
392 mata[1] = cancel_cb;
393 mata[2] = data;
395 acct = purple_connection_get_account(gc);
396 buddies = purple_blist_find_buddies(acct, NULL);
397 buddies = g_slist_sort(buddies, fb_buddy_cmp);
399 fields = purple_request_fields_new();
400 group = purple_request_field_group_new(NULL);
401 purple_request_fields_add_group(fields, group);
403 field = purple_request_field_list_new("buddy", NULL);
404 purple_request_field_list_set_multi_select(field, multi);
405 purple_request_field_set_required(field, TRUE);
406 purple_request_field_group_add_field(group, field);
408 for (l = buddies; l != NULL; l = l->next) {
409 name = purple_buddy_get_name(l->data);
410 alias = purple_buddy_get_alias(l->data);
411 str = g_strdup_printf("%s (%s)", alias, name);
412 purple_request_field_list_add_icon(field, str, NULL, l->data);
413 g_free(str);
416 for (l = select; l != NULL; l = l->next) {
417 name = purple_buddy_get_name(l->data);
418 alias = purple_buddy_get_alias(l->data);
419 str = g_strdup_printf("%s (%s)", alias, name);
420 items = g_list_append(items, str);
423 purple_request_field_list_set_selected(field, items);
424 g_slist_free(buddies);
425 g_list_free_full(items, g_free);
427 cpar = purple_request_cpar_from_connection(gc);
428 return purple_request_fields(gc, title, primary, secondary, fields,
429 _("Ok"),
430 G_CALLBACK(fb_util_request_buddy_ok),
431 _("Cancel"),
432 G_CALLBACK(fb_util_request_buddy_cancel),
433 cpar, mata);
436 void
437 fb_util_serv_got_im(PurpleConnection *gc, const gchar *who, const gchar *text,
438 PurpleMessageFlags flags, guint64 timestamp)
440 const gchar *name;
441 PurpleAccount *acct;
442 PurpleIMConversation *conv;
443 PurpleMessage *msg;
445 if (!(flags & PURPLE_MESSAGE_SEND)) {
446 purple_serv_got_im(gc, who, text, flags, timestamp);
447 return;
450 acct = purple_connection_get_account(gc);
451 conv = purple_conversations_find_im_with_account(who, acct);
453 if (conv == NULL) {
454 conv = purple_im_conversation_new(acct, who);
457 name = purple_account_get_username(acct);
458 msg = purple_message_new_outgoing(name, text, flags);
459 purple_message_set_time(msg, timestamp);
460 purple_conversation_write_message(PURPLE_CONVERSATION(conv), msg);
463 void
464 fb_util_serv_got_chat_in(PurpleConnection *gc, gint id, const gchar *who,
465 const gchar *text, PurpleMessageFlags flags,
466 guint64 timestamp)
468 const gchar *name;
469 PurpleAccount *acct;
470 PurpleChatConversation *conv;
471 PurpleMessage *msg;
473 if (!(flags & PURPLE_MESSAGE_SEND)) {
474 purple_serv_got_chat_in(gc, id, who, flags, text, timestamp);
475 return;
478 acct = purple_connection_get_account(gc);
479 conv = purple_conversations_find_chat(gc, id);
481 name = purple_account_get_username(acct);
482 msg = purple_message_new_outgoing(name, text, flags);
483 purple_message_set_time(msg, timestamp);
484 purple_conversation_write_message(PURPLE_CONVERSATION(conv), msg);
487 gboolean
488 fb_util_strtest(const gchar *str, GAsciiType type)
490 gsize i;
491 gsize size;
492 guchar c;
494 g_return_val_if_fail(str != NULL, FALSE);
495 size = strlen(str);
497 for (i = 0; i < size; i++) {
498 c = (guchar) str[i];
500 if ((g_ascii_table[c] & type) == 0) {
501 return FALSE;
505 return TRUE;
508 gboolean
509 fb_util_zlib_test(const GByteArray *bytes)
511 guint8 b0;
512 guint8 b1;
514 g_return_val_if_fail(bytes != NULL, FALSE);
516 if (bytes->len < 2) {
517 return FALSE;
520 b0 = *(bytes->data + 0);
521 b1 = *(bytes->data + 1);
523 return ((((b0 << 8) | b1) % 31) == 0) && /* Check the header */
524 ((b0 & 0x0F) == 8 /* Z_DEFLATED */); /* Check the method */
527 static GByteArray *
528 fb_util_zlib_conv(GConverter *conv, const GByteArray *bytes, GError **error)
530 GByteArray *ret;
531 GConverterResult res;
532 gsize cize = 0;
533 gsize rize;
534 gsize wize;
535 guint8 data[1024];
537 ret = g_byte_array_new();
539 while (TRUE) {
540 rize = 0;
541 wize = 0;
543 res = g_converter_convert(conv,
544 bytes->data + cize,
545 bytes->len - cize,
546 data, sizeof data,
547 G_CONVERTER_INPUT_AT_END,
548 &rize, &wize, error);
550 switch (res) {
551 case G_CONVERTER_CONVERTED:
552 g_byte_array_append(ret, data, wize);
553 cize += rize;
554 break;
556 case G_CONVERTER_ERROR:
557 g_byte_array_free(ret, TRUE);
558 return NULL;
560 case G_CONVERTER_FINISHED:
561 g_byte_array_append(ret, data, wize);
562 return ret;
564 default:
565 break;
570 GByteArray *
571 fb_util_zlib_deflate(const GByteArray *bytes, GError **error)
573 GByteArray *ret;
574 GZlibCompressor *conv;
576 conv = g_zlib_compressor_new(G_ZLIB_COMPRESSOR_FORMAT_ZLIB, -1);
577 ret = fb_util_zlib_conv(G_CONVERTER(conv), bytes, error);
578 g_object_unref(conv);
579 return ret;
582 GByteArray *
583 fb_util_zlib_inflate(const GByteArray *bytes, GError **error)
585 GByteArray *ret;
586 GZlibDecompressor *conv;
588 conv = g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_ZLIB);
589 ret = fb_util_zlib_conv(G_CONVERTER(conv), bytes, error);
590 g_object_unref(conv);
591 return ret;