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
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
28 #include "buddylist.h"
29 #include "conversations.h"
30 #include "glibcompat.h"
38 fb_util_error_quark(void)
42 if (G_UNLIKELY(q
== 0)) {
43 q
= g_quark_from_static_string("fb-util-error-quark");
50 fb_util_account_find_buddy(PurpleAccount
*acct
, PurpleChatConversation
*chat
,
51 const gchar
*search
, GError
**error
)
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
);
70 !purple_chat_conversation_has_user(chat
, name
))
75 if (g_ascii_strcasecmp(name
, search
) == 0) {
80 if (g_ascii_strcasecmp(alias
, search
) == 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
);
95 g_slist_free(buddies
);
100 fb_util_debug(PurpleDebugLevel level
, const gchar
*format
, ...)
104 va_start(ap
, format
);
105 fb_util_vdebug(level
, format
, ap
);
110 fb_util_vdebug(PurpleDebugLevel level
, const gchar
*format
, va_list ap
)
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()))
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
);
136 fb_util_debug_misc(const gchar
*format
, ...)
140 va_start(ap
, format
);
141 fb_util_vdebug(PURPLE_DEBUG_MISC
, format
, ap
);
146 fb_util_debug_info(const gchar
*format
, ...)
150 va_start(ap
, format
);
151 fb_util_vdebug(PURPLE_DEBUG_INFO
, format
, ap
);
156 fb_util_debug_warning(const gchar
*format
, ...)
160 va_start(ap
, format
);
161 fb_util_vdebug(PURPLE_DEBUG_WARNING
, format
, ap
);
166 fb_util_debug_error(const gchar
*format
, ...)
170 va_start(ap
, format
);
171 fb_util_vdebug(PURPLE_DEBUG_ERROR
, format
, ap
);
176 fb_util_debug_fatal(const gchar
*format
, ...)
180 va_start(ap
, format
);
181 fb_util_vdebug(PURPLE_DEBUG_FATAL
, format
, ap
);
186 fb_util_debug_hexdump(PurpleDebugLevel level
, const GByteArray
*bytes
,
187 const gchar
*format
, ...)
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
);
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 ",
215 g_string_append(gstr
, " ");
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
)) {
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
);
246 fb_util_get_locale(void)
248 const gchar
* const *langs
;
253 static const gchar chrs
[] = {'.', '@'};
255 langs
= g_get_language_names();
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
]);
266 return g_strndup(lang
, chr
- lang
);
270 return g_strdup(lang
);
274 fb_util_rand_alnum(guint len
)
281 static const gchar chars
[] =
282 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
283 "abcdefghijklmnopqrstuvwxyz"
285 static const gsize charc
= G_N_ELEMENTS(chars
) - 1;
287 g_return_val_if_fail(len
> 0, NULL
);
289 ret
= g_new(gchar
, len
+ 1);
291 for (i
= 0; i
< len
; i
++) {
292 j
= g_rand_int_range(rand
, 0, charc
);
302 fb_util_request_buddy_ok(gpointer
*mata
, PurpleRequestFields
*fields
)
304 FbUtilRequestBuddyFunc func
= mata
[0];
307 gpointer data
= mata
[2];
310 PurpleRequestField
*field
;
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
);
333 fb_util_request_buddy_cancel(gpointer
*mata
, PurpleRequestFields
*fields
)
335 FbUtilRequestBuddyFunc func
= mata
[1];
336 gpointer data
= mata
[2];
346 fb_buddy_cmp(gconstpointer a
, gconstpointer b
)
348 PurpleBuddy
*pba
, *pbb
;
349 gint alias_verdict
, name_verdict
;
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
);
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
);
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
)
385 PurpleRequestCommonParameters
*cpar
;
386 PurpleRequestField
*field
;
387 PurpleRequestFieldGroup
*group
;
388 PurpleRequestFields
*fields
;
390 mata
= g_new0(gpointer
, 3);
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
);
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
,
430 G_CALLBACK(fb_util_request_buddy_ok
),
432 G_CALLBACK(fb_util_request_buddy_cancel
),
437 fb_util_serv_got_im(PurpleConnection
*gc
, const gchar
*who
, const gchar
*text
,
438 PurpleMessageFlags flags
, guint64 timestamp
)
442 PurpleIMConversation
*conv
;
445 if (!(flags
& PURPLE_MESSAGE_SEND
)) {
446 purple_serv_got_im(gc
, who
, text
, flags
, timestamp
);
450 acct
= purple_connection_get_account(gc
);
451 conv
= purple_conversations_find_im_with_account(who
, acct
);
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
);
464 fb_util_serv_got_chat_in(PurpleConnection
*gc
, gint id
, const gchar
*who
,
465 const gchar
*text
, PurpleMessageFlags flags
,
470 PurpleChatConversation
*conv
;
473 if (!(flags
& PURPLE_MESSAGE_SEND
)) {
474 purple_serv_got_chat_in(gc
, id
, who
, flags
, text
, timestamp
);
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
);
488 fb_util_strtest(const gchar
*str
, GAsciiType type
)
494 g_return_val_if_fail(str
!= NULL
, FALSE
);
497 for (i
= 0; i
< size
; i
++) {
500 if ((g_ascii_table
[c
] & type
) == 0) {
509 fb_util_zlib_test(const GByteArray
*bytes
)
514 g_return_val_if_fail(bytes
!= NULL
, FALSE
);
516 if (bytes
->len
< 2) {
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 */
528 fb_util_zlib_conv(GConverter
*conv
, const GByteArray
*bytes
, GError
**error
)
531 GConverterResult res
;
537 ret
= g_byte_array_new();
543 res
= g_converter_convert(conv
,
547 G_CONVERTER_INPUT_AT_END
,
548 &rize
, &wize
, error
);
551 case G_CONVERTER_CONVERTED
:
552 g_byte_array_append(ret
, data
, wize
);
556 case G_CONVERTER_ERROR
:
557 g_byte_array_free(ret
, TRUE
);
560 case G_CONVERTER_FINISHED
:
561 g_byte_array_append(ret
, data
, wize
);
571 fb_util_zlib_deflate(const GByteArray
*bytes
, GError
**error
)
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
);
583 fb_util_zlib_inflate(const GByteArray
*bytes
, GError
**error
)
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
);