| 1 /** |
|
| 2 * @file gg.c Gadu-Gadu protocol plugin |
|
| 3 * |
|
| 4 * purple |
|
| 5 * |
|
| 6 * Copyright (C) 2005 Bartosz Oler <bartosz@bzimage.us> |
|
| 7 * |
|
| 8 * Some parts of the code are adapted or taken from the previous implementation |
|
| 9 * of this plugin written by Arkadiusz Miskiewicz <misiek@pld.org.pl> |
|
| 10 * Some parts Copyright (C) 2009 Krzysztof Klinikowski <grommasher@gmail.com> |
|
| 11 * |
|
| 12 * Thanks to Google's Summer of Code Program. |
|
| 13 * |
|
| 14 * This program is free software; you can redistribute it and/or modify |
|
| 15 * it under the terms of the GNU General Public License as published by |
|
| 16 * the Free Software Foundation; either version 2 of the License, or |
|
| 17 * (at your option) any later version. |
|
| 18 * |
|
| 19 * This program is distributed in the hope that it will be useful, |
|
| 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 22 * GNU General Public License for more details. |
|
| 23 * |
|
| 24 * You should have received a copy of the GNU General Public License |
|
| 25 * along with this program; if not, write to the Free Software |
|
| 26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
|
| 27 */ |
|
| 28 |
|
| 29 #include "internal.h" |
|
| 30 |
|
| 31 #include "plugin.h" |
|
| 32 #include "version.h" |
|
| 33 #include "notify.h" |
|
| 34 #include "status.h" |
|
| 35 #include "blist.h" |
|
| 36 #include "accountopt.h" |
|
| 37 #include "debug.h" |
|
| 38 #include "glibcompat.h" |
|
| 39 #include "util.h" |
|
| 40 #include "request.h" |
|
| 41 #include "xmlnode.h" |
|
| 42 |
|
| 43 #include <libgadu.h> |
|
| 44 |
|
| 45 #include "gg.h" |
|
| 46 #include "confer.h" |
|
| 47 #include "search.h" |
|
| 48 #include "buddylist.h" |
|
| 49 #include "gg-utils.h" |
|
| 50 |
|
| 51 #define DISABLE_AVATARS 1 |
|
| 52 |
|
| 53 static PurplePlugin *my_protocol = NULL; |
|
| 54 |
|
| 55 /* Prototypes */ |
|
| 56 static void ggp_set_status(PurpleAccount *account, PurpleStatus *status); |
|
| 57 static int ggp_to_gg_status(PurpleStatus *status, char **msg); |
|
| 58 |
|
| 59 /* ---------------------------------------------------------------------- */ |
|
| 60 /* ----- EXTERNAL CALLBACKS --------------------------------------------- */ |
|
| 61 /* ---------------------------------------------------------------------- */ |
|
| 62 |
|
| 63 |
|
| 64 /* ----- HELPERS -------------------------------------------------------- */ |
|
| 65 |
|
| 66 static PurpleInputCondition |
|
| 67 ggp_tcpsocket_inputcond_gg_to_purple(enum gg_check_t check) |
|
| 68 { |
|
| 69 PurpleInputCondition cond = 0; |
|
| 70 |
|
| 71 if (check & GG_CHECK_READ) |
|
| 72 cond |= PURPLE_INPUT_READ; |
|
| 73 if (check & GG_CHECK_WRITE) |
|
| 74 cond |= PURPLE_INPUT_WRITE; |
|
| 75 |
|
| 76 return cond; |
|
| 77 } |
|
| 78 |
|
| 79 /** |
|
| 80 * Set up libgadu's proxy. |
|
| 81 * |
|
| 82 * @param account Account for which to set up the proxy. |
|
| 83 * |
|
| 84 * @return Zero if proxy setup is valid, otherwise -1. |
|
| 85 */ |
|
| 86 static int ggp_setup_proxy(PurpleAccount *account) |
|
| 87 { |
|
| 88 PurpleProxyInfo *gpi; |
|
| 89 |
|
| 90 gpi = purple_proxy_get_setup(account); |
|
| 91 |
|
| 92 if ((purple_proxy_info_get_type(gpi) != PURPLE_PROXY_NONE) && |
|
| 93 (purple_proxy_info_get_host(gpi) == NULL || |
|
| 94 purple_proxy_info_get_port(gpi) <= 0)) { |
|
| 95 |
|
| 96 gg_proxy_enabled = 0; |
|
| 97 purple_notify_error(NULL, NULL, _("Invalid proxy settings"), |
|
| 98 _("Either the host name or port number specified for your given proxy type is invalid.")); |
|
| 99 return -1; |
|
| 100 } else if (purple_proxy_info_get_type(gpi) != PURPLE_PROXY_NONE) { |
|
| 101 gg_proxy_enabled = 1; |
|
| 102 gg_proxy_host = g_strdup(purple_proxy_info_get_host(gpi)); |
|
| 103 gg_proxy_port = purple_proxy_info_get_port(gpi); |
|
| 104 gg_proxy_username = g_strdup(purple_proxy_info_get_username(gpi)); |
|
| 105 gg_proxy_password = g_strdup(purple_proxy_info_get_password(gpi)); |
|
| 106 } else { |
|
| 107 gg_proxy_enabled = 0; |
|
| 108 } |
|
| 109 |
|
| 110 return 0; |
|
| 111 } |
|
| 112 |
|
| 113 /* }}} */ |
|
| 114 |
|
| 115 /* ---------------------------------------------------------------------- */ |
|
| 116 |
|
| 117 static void ggp_callback_buddylist_save_ok(PurpleConnection *gc, const char *filename) |
|
| 118 { |
|
| 119 PurpleAccount *account = purple_connection_get_account(gc); |
|
| 120 |
|
| 121 char *buddylist = ggp_buddylist_dump(account); |
|
| 122 |
|
| 123 purple_debug_info("gg", "Saving...\n"); |
|
| 124 purple_debug_info("gg", "file = %s\n", filename); |
|
| 125 |
|
| 126 if (buddylist == NULL) { |
|
| 127 purple_notify_info(account, _("Save Buddylist..."), |
|
| 128 _("Your buddylist is empty, nothing was written to the file."), |
|
| 129 NULL); |
|
| 130 return; |
|
| 131 } |
|
| 132 |
|
| 133 if(purple_util_write_data_to_file_absolute(filename, buddylist, -1)) { |
|
| 134 purple_notify_info(account, _("Save Buddylist..."), |
|
| 135 _("Buddylist saved successfully!"), NULL); |
|
| 136 } else { |
|
| 137 gchar *primary = g_strdup_printf( |
|
| 138 _("Couldn't write buddy list for %s to %s"), |
|
| 139 purple_account_get_username(account), filename); |
|
| 140 purple_notify_error(account, _("Save Buddylist..."), |
|
| 141 primary, NULL); |
|
| 142 g_free(primary); |
|
| 143 } |
|
| 144 |
|
| 145 g_free(buddylist); |
|
| 146 } |
|
| 147 |
|
| 148 static void ggp_callback_buddylist_load_ok(PurpleConnection *gc, gchar *file) |
|
| 149 { |
|
| 150 PurpleAccount *account = purple_connection_get_account(gc); |
|
| 151 GError *error = NULL; |
|
| 152 char *buddylist = NULL; |
|
| 153 gsize length; |
|
| 154 |
|
| 155 purple_debug_info("gg", "file_name = %s\n", file); |
|
| 156 |
|
| 157 if (!g_file_get_contents(file, &buddylist, &length, &error)) { |
|
| 158 purple_notify_error(account, |
|
| 159 _("Couldn't load buddylist"), |
|
| 160 _("Couldn't load buddylist"), |
|
| 161 error->message); |
|
| 162 |
|
| 163 purple_debug_error("gg", |
|
| 164 "Couldn't load buddylist. file = %s; error = %s\n", |
|
| 165 file, error->message); |
|
| 166 |
|
| 167 g_error_free(error); |
|
| 168 |
|
| 169 return; |
|
| 170 } |
|
| 171 |
|
| 172 ggp_buddylist_load(gc, buddylist); |
|
| 173 g_free(buddylist); |
|
| 174 |
|
| 175 purple_notify_info(account, |
|
| 176 _("Load Buddylist..."), |
|
| 177 _("Buddylist loaded successfully!"), NULL); |
|
| 178 } |
|
| 179 /* }}} */ |
|
| 180 |
|
| 181 /* |
|
| 182 */ |
|
| 183 /* static void ggp_action_buddylist_save(PurplePluginAction *action) {{{ */ |
|
| 184 static void ggp_action_buddylist_save(PurplePluginAction *action) |
|
| 185 { |
|
| 186 PurpleConnection *gc = (PurpleConnection *)action->context; |
|
| 187 |
|
| 188 purple_request_file(action, _("Save buddylist..."), NULL, TRUE, |
|
| 189 G_CALLBACK(ggp_callback_buddylist_save_ok), NULL, |
|
| 190 purple_connection_get_account(gc), NULL, NULL, |
|
| 191 gc); |
|
| 192 } |
|
| 193 |
|
| 194 static void ggp_action_buddylist_load(PurplePluginAction *action) |
|
| 195 { |
|
| 196 PurpleConnection *gc = (PurpleConnection *)action->context; |
|
| 197 |
|
| 198 purple_request_file(action, _("Load buddylist from file..."), NULL, |
|
| 199 FALSE, |
|
| 200 G_CALLBACK(ggp_callback_buddylist_load_ok), NULL, |
|
| 201 purple_connection_get_account(gc), NULL, NULL, |
|
| 202 gc); |
|
| 203 } |
|
| 204 |
|
| 205 /* ----- PUBLIC DIRECTORY SEARCH ---------------------------------------- */ |
|
| 206 |
|
| 207 static void ggp_callback_show_next(PurpleConnection *gc, GList *row, gpointer user_data) |
|
| 208 { |
|
| 209 GGPInfo *info = gc->proto_data; |
|
| 210 GGPSearchForm *form = user_data; |
|
| 211 guint32 seq; |
|
| 212 |
|
| 213 form->page_number++; |
|
| 214 |
|
| 215 ggp_search_remove(info->searches, form->seq); |
|
| 216 purple_debug_info("gg", "ggp_callback_show_next(): Removed seq %u\n", |
|
| 217 form->seq); |
|
| 218 |
|
| 219 seq = ggp_search_start(gc, form); |
|
| 220 ggp_search_add(info->searches, seq, form); |
|
| 221 purple_debug_info("gg", "ggp_callback_show_next(): Added seq %u\n", |
|
| 222 seq); |
|
| 223 } |
|
| 224 |
|
| 225 static void ggp_callback_add_buddy(PurpleConnection *gc, GList *row, gpointer user_data) |
|
| 226 { |
|
| 227 purple_blist_request_add_buddy(purple_connection_get_account(gc), |
|
| 228 g_list_nth_data(row, 0), NULL, NULL); |
|
| 229 } |
|
| 230 |
|
| 231 static void ggp_callback_im(PurpleConnection *gc, GList *row, gpointer user_data) |
|
| 232 { |
|
| 233 PurpleAccount *account; |
|
| 234 PurpleConversation *conv; |
|
| 235 char *name; |
|
| 236 |
|
| 237 account = purple_connection_get_account(gc); |
|
| 238 |
|
| 239 name = g_list_nth_data(row, 0); |
|
| 240 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, name); |
|
| 241 purple_conversation_present(conv); |
|
| 242 } |
|
| 243 |
|
| 244 static void ggp_callback_find_buddies(PurpleConnection *gc, PurpleRequestFields *fields) |
|
| 245 { |
|
| 246 GGPInfo *info = gc->proto_data; |
|
| 247 GGPSearchForm *form; |
|
| 248 guint32 seq; |
|
| 249 |
|
| 250 form = ggp_search_form_new(GGP_SEARCH_TYPE_FULL); |
|
| 251 |
|
| 252 form->user_data = info; |
|
| 253 form->lastname = g_strdup( |
|
| 254 purple_request_fields_get_string(fields, "lastname")); |
|
| 255 form->firstname = g_strdup( |
|
| 256 purple_request_fields_get_string(fields, "firstname")); |
|
| 257 form->nickname = g_strdup( |
|
| 258 purple_request_fields_get_string(fields, "nickname")); |
|
| 259 form->city = g_strdup( |
|
| 260 purple_request_fields_get_string(fields, "city")); |
|
| 261 form->birthyear = g_strdup( |
|
| 262 purple_request_fields_get_string(fields, "year")); |
|
| 263 |
|
| 264 switch (purple_request_fields_get_choice(fields, "gender")) { |
|
| 265 case 1: |
|
| 266 form->gender = g_strdup(GG_PUBDIR50_GENDER_MALE); |
|
| 267 break; |
|
| 268 case 2: |
|
| 269 form->gender = g_strdup(GG_PUBDIR50_GENDER_FEMALE); |
|
| 270 break; |
|
| 271 default: |
|
| 272 form->gender = NULL; |
|
| 273 break; |
|
| 274 } |
|
| 275 |
|
| 276 form->active = purple_request_fields_get_bool(fields, "active") |
|
| 277 ? g_strdup(GG_PUBDIR50_ACTIVE_TRUE) : NULL; |
|
| 278 |
|
| 279 seq = ggp_search_start(gc, form); |
|
| 280 ggp_search_add(info->searches, seq, form); |
|
| 281 purple_debug_info("gg", "ggp_callback_find_buddies(): Added seq %u\n", |
|
| 282 seq); |
|
| 283 } |
|
| 284 |
|
| 285 static void ggp_find_buddies(PurplePluginAction *action) |
|
| 286 { |
|
| 287 PurpleConnection *gc = (PurpleConnection *)action->context; |
|
| 288 |
|
| 289 PurpleRequestFields *fields; |
|
| 290 PurpleRequestFieldGroup *group; |
|
| 291 PurpleRequestField *field; |
|
| 292 |
|
| 293 fields = purple_request_fields_new(); |
|
| 294 group = purple_request_field_group_new(NULL); |
|
| 295 purple_request_fields_add_group(fields, group); |
|
| 296 |
|
| 297 field = purple_request_field_string_new("lastname", |
|
| 298 _("Last name"), NULL, FALSE); |
|
| 299 purple_request_field_string_set_masked(field, FALSE); |
|
| 300 purple_request_field_group_add_field(group, field); |
|
| 301 |
|
| 302 field = purple_request_field_string_new("firstname", |
|
| 303 _("First name"), NULL, FALSE); |
|
| 304 purple_request_field_string_set_masked(field, FALSE); |
|
| 305 purple_request_field_group_add_field(group, field); |
|
| 306 |
|
| 307 field = purple_request_field_string_new("nickname", |
|
| 308 _("Nickname"), NULL, FALSE); |
|
| 309 purple_request_field_string_set_masked(field, FALSE); |
|
| 310 purple_request_field_group_add_field(group, field); |
|
| 311 |
|
| 312 field = purple_request_field_string_new("city", |
|
| 313 _("City"), NULL, FALSE); |
|
| 314 purple_request_field_string_set_masked(field, FALSE); |
|
| 315 purple_request_field_group_add_field(group, field); |
|
| 316 |
|
| 317 field = purple_request_field_string_new("year", |
|
| 318 _("Year of birth"), NULL, FALSE); |
|
| 319 purple_request_field_group_add_field(group, field); |
|
| 320 |
|
| 321 field = purple_request_field_choice_new("gender", _("Gender"), 0); |
|
| 322 purple_request_field_choice_add(field, _("Male or female")); |
|
| 323 purple_request_field_choice_add(field, _("Male")); |
|
| 324 purple_request_field_choice_add(field, _("Female")); |
|
| 325 purple_request_field_group_add_field(group, field); |
|
| 326 |
|
| 327 field = purple_request_field_bool_new("active", |
|
| 328 _("Only online"), FALSE); |
|
| 329 purple_request_field_group_add_field(group, field); |
|
| 330 |
|
| 331 purple_request_fields(gc, |
|
| 332 _("Find buddies"), |
|
| 333 _("Find buddies"), |
|
| 334 _("Please, enter your search criteria below"), |
|
| 335 fields, |
|
| 336 _("OK"), G_CALLBACK(ggp_callback_find_buddies), |
|
| 337 _("Cancel"), NULL, |
|
| 338 purple_connection_get_account(gc), NULL, NULL, |
|
| 339 gc); |
|
| 340 } |
|
| 341 |
|
| 342 /* ----- CHANGE STATUS BROADCASTING ------------------------------------------------ */ |
|
| 343 |
|
| 344 static void ggp_action_change_status_broadcasting_ok(PurpleConnection *gc, PurpleRequestFields *fields) |
|
| 345 { |
|
| 346 GGPInfo *info = gc->proto_data; |
|
| 347 int selected_field; |
|
| 348 PurpleAccount *account = purple_connection_get_account(gc); |
|
| 349 PurpleStatus *status; |
|
| 350 |
|
| 351 selected_field = purple_request_fields_get_choice(fields, "status_broadcasting"); |
|
| 352 |
|
| 353 if (selected_field == 0) |
|
| 354 info->status_broadcasting = TRUE; |
|
| 355 else |
|
| 356 info->status_broadcasting = FALSE; |
|
| 357 |
|
| 358 status = purple_account_get_active_status(account); |
|
| 359 |
|
| 360 ggp_set_status(account, status); |
|
| 361 } |
|
| 362 |
|
| 363 static void ggp_action_change_status_broadcasting(PurplePluginAction *action) |
|
| 364 { |
|
| 365 PurpleConnection *gc = (PurpleConnection *)action->context; |
|
| 366 GGPInfo *info = gc->proto_data; |
|
| 367 |
|
| 368 PurpleRequestFields *fields; |
|
| 369 PurpleRequestFieldGroup *group; |
|
| 370 PurpleRequestField *field; |
|
| 371 |
|
| 372 fields = purple_request_fields_new(); |
|
| 373 group = purple_request_field_group_new(NULL); |
|
| 374 purple_request_fields_add_group(fields, group); |
|
| 375 |
|
| 376 field = purple_request_field_choice_new("status_broadcasting", _("Show status to:"), 0); |
|
| 377 purple_request_field_choice_add(field, _("All people")); |
|
| 378 purple_request_field_choice_add(field, _("Only buddies")); |
|
| 379 purple_request_field_group_add_field(group, field); |
|
| 380 |
|
| 381 if (info->status_broadcasting) |
|
| 382 purple_request_field_choice_set_default_value(field, 0); |
|
| 383 else |
|
| 384 purple_request_field_choice_set_default_value(field, 1); |
|
| 385 |
|
| 386 purple_request_fields(gc, |
|
| 387 _("Change status broadcasting"), |
|
| 388 _("Change status broadcasting"), |
|
| 389 _("Please, select who can see your status"), |
|
| 390 fields, |
|
| 391 _("OK"), G_CALLBACK(ggp_action_change_status_broadcasting_ok), |
|
| 392 _("Cancel"), NULL, |
|
| 393 purple_connection_get_account(gc), NULL, NULL, |
|
| 394 gc); |
|
| 395 } |
|
| 396 |
|
| 397 /* ----- CONFERENCES ---------------------------------------------------- */ |
|
| 398 |
|
| 399 static void ggp_callback_add_to_chat_ok(PurpleBuddy *buddy, PurpleRequestFields *fields) |
|
| 400 { |
|
| 401 PurpleConnection *conn; |
|
| 402 PurpleRequestField *field; |
|
| 403 GList *sel; |
|
| 404 |
|
| 405 conn = purple_account_get_connection(purple_buddy_get_account(buddy)); |
|
| 406 |
|
| 407 g_return_if_fail(conn != NULL); |
|
| 408 |
|
| 409 field = purple_request_fields_get_field(fields, "name"); |
|
| 410 sel = purple_request_field_list_get_selected(field); |
|
| 411 |
|
| 412 if (sel == NULL) { |
|
| 413 purple_debug_error("gg", "No chat selected\n"); |
|
| 414 return; |
|
| 415 } |
|
| 416 |
|
| 417 ggp_confer_participants_add_uin(conn, sel->data, |
|
| 418 ggp_str_to_uin(purple_buddy_get_name(buddy))); |
|
| 419 } |
|
| 420 |
|
| 421 static void ggp_bmenu_add_to_chat(PurpleBlistNode *node, gpointer ignored) |
|
| 422 { |
|
| 423 PurpleBuddy *buddy; |
|
| 424 PurpleConnection *gc; |
|
| 425 GGPInfo *info; |
|
| 426 |
|
| 427 PurpleRequestFields *fields; |
|
| 428 PurpleRequestFieldGroup *group; |
|
| 429 PurpleRequestField *field; |
|
| 430 |
|
| 431 GList *l; |
|
| 432 gchar *msg; |
|
| 433 |
|
| 434 buddy = (PurpleBuddy *)node; |
|
| 435 gc = purple_account_get_connection(purple_buddy_get_account(buddy)); |
|
| 436 info = gc->proto_data; |
|
| 437 |
|
| 438 fields = purple_request_fields_new(); |
|
| 439 group = purple_request_field_group_new(NULL); |
|
| 440 purple_request_fields_add_group(fields, group); |
|
| 441 |
|
| 442 field = purple_request_field_list_new("name", "Chat name"); |
|
| 443 for (l = info->chats; l != NULL; l = l->next) { |
|
| 444 GGPChat *chat = l->data; |
|
| 445 purple_request_field_list_add(field, chat->name, chat->name); |
|
| 446 } |
|
| 447 purple_request_field_group_add_field(group, field); |
|
| 448 |
|
| 449 msg = g_strdup_printf(_("Select a chat for buddy: %s"), |
|
| 450 purple_buddy_get_alias(buddy)); |
|
| 451 purple_request_fields(gc, |
|
| 452 _("Add to chat..."), |
|
| 453 _("Add to chat..."), |
|
| 454 msg, |
|
| 455 fields, |
|
| 456 _("Add"), G_CALLBACK(ggp_callback_add_to_chat_ok), |
|
| 457 _("Cancel"), NULL, |
|
| 458 purple_connection_get_account(gc), NULL, NULL, |
|
| 459 buddy); |
|
| 460 g_free(msg); |
|
| 461 } |
|
| 462 |
|
| 463 /* ----- BLOCK BUDDIES -------------------------------------------------- */ |
|
| 464 |
|
| 465 static void ggp_add_deny(PurpleConnection *gc, const char *who) |
|
| 466 { |
|
| 467 GGPInfo *info = gc->proto_data; |
|
| 468 uin_t uin = ggp_str_to_uin(who); |
|
| 469 |
|
| 470 purple_debug_info("gg", "ggp_add_deny: %u\n", uin); |
|
| 471 |
|
| 472 gg_remove_notify_ex(info->session, uin, GG_USER_NORMAL); |
|
| 473 gg_add_notify_ex(info->session, uin, GG_USER_BLOCKED); |
|
| 474 } |
|
| 475 |
|
| 476 static void ggp_rem_deny(PurpleConnection *gc, const char *who) |
|
| 477 { |
|
| 478 GGPInfo *info = gc->proto_data; |
|
| 479 uin_t uin = ggp_str_to_uin(who); |
|
| 480 |
|
| 481 purple_debug_info("gg", "ggp_rem_deny: %u\n", uin); |
|
| 482 |
|
| 483 gg_remove_notify_ex(info->session, uin, GG_USER_BLOCKED); |
|
| 484 gg_add_notify_ex(info->session, uin, GG_USER_NORMAL); |
|
| 485 } |
|
| 486 |
|
| 487 /* ---------------------------------------------------------------------- */ |
|
| 488 /* ----- INTERNAL CALLBACKS --------------------------------------------- */ |
|
| 489 /* ---------------------------------------------------------------------- */ |
|
| 490 |
|
| 491 #if !DISABLE_AVATARS |
|
| 492 |
|
| 493 struct gg_fetch_avatar_data |
|
| 494 { |
|
| 495 PurpleConnection *gc; |
|
| 496 gchar *uin; |
|
| 497 gchar *avatar_url; |
|
| 498 }; |
|
| 499 |
|
| 500 |
|
| 501 static void gg_fetch_avatar_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, |
|
| 502 const gchar *data, size_t len, const gchar *error_message) { |
|
| 503 struct gg_fetch_avatar_data *d = user_data; |
|
| 504 PurpleAccount *account; |
|
| 505 PurpleBuddy *buddy; |
|
| 506 gpointer buddy_icon_data; |
|
| 507 |
|
| 508 purple_debug_info("gg", "gg_fetch_avatar_cb: got avatar image for %s\n", |
|
| 509 d->uin); |
|
| 510 |
|
| 511 /* FIXME: This shouldn't be necessary */ |
|
| 512 if (!PURPLE_CONNECTION_IS_VALID(d->gc)) { |
|
| 513 g_free(d->uin); |
|
| 514 g_free(d->avatar_url); |
|
| 515 g_free(d); |
|
| 516 g_return_if_reached(); |
|
| 517 } |
|
| 518 |
|
| 519 account = purple_connection_get_account(d->gc); |
|
| 520 buddy = purple_find_buddy(account, d->uin); |
|
| 521 |
|
| 522 if (buddy == NULL) |
|
| 523 goto out; |
|
| 524 |
|
| 525 buddy_icon_data = g_memdup2(data, len); |
|
| 526 |
|
| 527 purple_buddy_icons_set_for_user(account, purple_buddy_get_name(buddy), |
|
| 528 buddy_icon_data, len, d->avatar_url); |
|
| 529 purple_debug_info("gg", "gg_fetch_avatar_cb: UIN %s should have avatar " |
|
| 530 "now\n", d->uin); |
|
| 531 |
|
| 532 out: |
|
| 533 g_free(d->uin); |
|
| 534 g_free(d->avatar_url); |
|
| 535 g_free(d); |
|
| 536 } |
|
| 537 |
|
| 538 static void gg_get_avatar_url_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, |
|
| 539 const gchar *url_text, size_t len, const gchar *error_message) { |
|
| 540 struct gg_fetch_avatar_data *data; |
|
| 541 PurpleConnection *gc = user_data; |
|
| 542 PurpleAccount *account; |
|
| 543 PurpleBuddy *buddy; |
|
| 544 const char *uin; |
|
| 545 const char *is_blank; |
|
| 546 const char *checksum; |
|
| 547 |
|
| 548 gchar *bigavatar = NULL; |
|
| 549 xmlnode *xml = NULL; |
|
| 550 xmlnode *xmlnode_users; |
|
| 551 xmlnode *xmlnode_user; |
|
| 552 xmlnode *xmlnode_avatars; |
|
| 553 xmlnode *xmlnode_avatar; |
|
| 554 xmlnode *xmlnode_bigavatar; |
|
| 555 |
|
| 556 g_return_if_fail(PURPLE_CONNECTION_IS_VALID(gc)); |
|
| 557 account = purple_connection_get_account(gc); |
|
| 558 |
|
| 559 if (error_message != NULL) |
|
| 560 purple_debug_error("gg", "gg_get_avatars_cb error: %s\n", error_message); |
|
| 561 else if (len > 0 && url_text && *url_text) { |
|
| 562 xml = xmlnode_from_str(url_text, -1); |
|
| 563 if (xml == NULL) |
|
| 564 goto out; |
|
| 565 |
|
| 566 xmlnode_users = xmlnode_get_child(xml, "users"); |
|
| 567 if (xmlnode_users == NULL) |
|
| 568 goto out; |
|
| 569 |
|
| 570 xmlnode_user = xmlnode_get_child(xmlnode_users, "user"); |
|
| 571 if (xmlnode_user == NULL) |
|
| 572 goto out; |
|
| 573 |
|
| 574 uin = xmlnode_get_attrib(xmlnode_user, "uin"); |
|
| 575 |
|
| 576 xmlnode_avatars = xmlnode_get_child(xmlnode_user, "avatars"); |
|
| 577 if (xmlnode_avatars == NULL) |
|
| 578 goto out; |
|
| 579 |
|
| 580 xmlnode_avatar = xmlnode_get_child(xmlnode_avatars, "avatar"); |
|
| 581 if (xmlnode_avatar == NULL) |
|
| 582 goto out; |
|
| 583 |
|
| 584 xmlnode_bigavatar = xmlnode_get_child(xmlnode_avatar, "originBigAvatar"); |
|
| 585 if (xmlnode_bigavatar == NULL) |
|
| 586 goto out; |
|
| 587 |
|
| 588 is_blank = xmlnode_get_attrib(xmlnode_avatar, "blank"); |
|
| 589 bigavatar = xmlnode_get_data(xmlnode_bigavatar); |
|
| 590 |
|
| 591 purple_debug_info("gg", "gg_get_avatar_url_cb: UIN %s, IS_BLANK %s, " |
|
| 592 "URL %s\n", |
|
| 593 uin ? uin : "(null)", is_blank ? is_blank : "(null)", |
|
| 594 bigavatar ? bigavatar : "(null)"); |
|
| 595 |
|
| 596 if (uin != NULL && bigavatar != NULL) { |
|
| 597 buddy = purple_find_buddy(account, uin); |
|
| 598 if (buddy == NULL) |
|
| 599 goto out; |
|
| 600 |
|
| 601 checksum = purple_buddy_icons_get_checksum_for_user(buddy); |
|
| 602 |
|
| 603 if (purple_strequal(is_blank, "1")) { |
|
| 604 purple_buddy_icons_set_for_user(account, |
|
| 605 purple_buddy_get_name(buddy), NULL, 0, NULL); |
|
| 606 } else if (!purple_strequal(checksum, bigavatar)) { |
|
| 607 data = g_new0(struct gg_fetch_avatar_data, 1); |
|
| 608 data->gc = gc; |
|
| 609 data->uin = g_strdup(uin); |
|
| 610 data->avatar_url = g_strdup(bigavatar); |
|
| 611 |
|
| 612 purple_debug_info("gg", "gg_get_avatar_url_cb: " |
|
| 613 "requesting avatar for %s\n", uin); |
|
| 614 url_data = purple_util_fetch_url_request_len_with_account(account, |
|
| 615 bigavatar, TRUE, "Mozilla/4.0 (compatible; MSIE 5.0)", |
|
| 616 FALSE, NULL, FALSE, -1, gg_fetch_avatar_cb, data); |
|
| 617 } |
|
| 618 } |
|
| 619 } |
|
| 620 |
|
| 621 out: |
|
| 622 if (xml) |
|
| 623 xmlnode_free(xml); |
|
| 624 g_free(bigavatar); |
|
| 625 } |
|
| 626 |
|
| 627 #endif |
|
| 628 |
|
| 629 /** |
|
| 630 * Try to update avatar of the buddy. |
|
| 631 * |
|
| 632 * @param gc PurpleConnection |
|
| 633 * @param uin UIN of the buddy. |
|
| 634 */ |
|
| 635 static void ggp_update_buddy_avatar(PurpleConnection *gc, uin_t uin) |
|
| 636 { |
|
| 637 #if DISABLE_AVATARS |
|
| 638 purple_debug_warning("gg", "ggp_update_buddy_avatar: disabled, please " |
|
| 639 "update to 3.0.0, when available\n"); |
|
| 640 #else |
|
| 641 gchar *avatarurl; |
|
| 642 PurpleUtilFetchUrlData *url_data; |
|
| 643 |
|
| 644 purple_debug_info("gg", "ggp_update_buddy_avatar(gc, %u)\n", uin); |
|
| 645 |
|
| 646 avatarurl = g_strdup_printf("http://api.gadu-gadu.pl/avatars/%u/0.xml", uin); |
|
| 647 |
|
| 648 url_data = purple_util_fetch_url_request_len_with_account( |
|
| 649 purple_connection_get_account(gc), avatarurl, TRUE, |
|
| 650 "Mozilla/4.0 (compatible; MSIE 5.5)", FALSE, NULL, FALSE, -1, |
|
| 651 gg_get_avatar_url_cb, gc); |
|
| 652 |
|
| 653 g_free(avatarurl); |
|
| 654 #endif |
|
| 655 } |
|
| 656 |
|
| 657 /** |
|
| 658 * Handle change of the status of the buddy. |
|
| 659 * |
|
| 660 * @param gc PurpleConnection |
|
| 661 * @param uin UIN of the buddy. |
|
| 662 * @param status ID of the status. |
|
| 663 * @param descr Description. |
|
| 664 */ |
|
| 665 static void ggp_generic_status_handler(PurpleConnection *gc, uin_t uin, |
|
| 666 int status, const char *descr) |
|
| 667 { |
|
| 668 gchar *from; |
|
| 669 const char *st; |
|
| 670 char *status_msg = NULL; |
|
| 671 |
|
| 672 ggp_update_buddy_avatar(gc, uin); |
|
| 673 |
|
| 674 from = g_strdup_printf("%u", uin); |
|
| 675 |
|
| 676 switch (status) { |
|
| 677 case GG_STATUS_NOT_AVAIL: |
|
| 678 case GG_STATUS_NOT_AVAIL_DESCR: |
|
| 679 st = purple_primitive_get_id_from_type(PURPLE_STATUS_OFFLINE); |
|
| 680 break; |
|
| 681 case GG_STATUS_FFC: |
|
| 682 case GG_STATUS_FFC_DESCR: |
|
| 683 st = purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE); |
|
| 684 break; |
|
| 685 case GG_STATUS_AVAIL: |
|
| 686 case GG_STATUS_AVAIL_DESCR: |
|
| 687 st = purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE); |
|
| 688 break; |
|
| 689 case GG_STATUS_BUSY: |
|
| 690 case GG_STATUS_BUSY_DESCR: |
|
| 691 st = purple_primitive_get_id_from_type(PURPLE_STATUS_AWAY); |
|
| 692 break; |
|
| 693 case GG_STATUS_DND: |
|
| 694 case GG_STATUS_DND_DESCR: |
|
| 695 st = purple_primitive_get_id_from_type(PURPLE_STATUS_UNAVAILABLE); |
|
| 696 break; |
|
| 697 case GG_STATUS_BLOCKED: |
|
| 698 /* user is blocking us.... */ |
|
| 699 st = "blocked"; |
|
| 700 break; |
|
| 701 default: |
|
| 702 st = purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE); |
|
| 703 purple_debug_info("gg", |
|
| 704 "GG_EVENT_NOTIFY: Unknown status: %d\n", status); |
|
| 705 break; |
|
| 706 } |
|
| 707 |
|
| 708 if (descr != NULL) { |
|
| 709 status_msg = g_strdup(descr); |
|
| 710 g_strstrip(status_msg); |
|
| 711 if (status_msg[0] == '\0') { |
|
| 712 g_free(status_msg); |
|
| 713 status_msg = NULL; |
|
| 714 } |
|
| 715 } |
|
| 716 |
|
| 717 purple_debug_info("gg", "status of %u is %s [%s]\n", uin, st, |
|
| 718 status_msg ? status_msg : ""); |
|
| 719 if (status_msg == NULL) { |
|
| 720 purple_prpl_got_user_status(purple_connection_get_account(gc), |
|
| 721 from, st, NULL); |
|
| 722 } else { |
|
| 723 purple_prpl_got_user_status(purple_connection_get_account(gc), |
|
| 724 from, st, "message", status_msg, NULL); |
|
| 725 g_free(status_msg); |
|
| 726 } |
|
| 727 g_free(from); |
|
| 728 } |
|
| 729 |
|
| 730 static void ggp_sr_close_cb(gpointer user_data) |
|
| 731 { |
|
| 732 GGPSearchForm *form = user_data; |
|
| 733 GGPInfo *info = form->user_data; |
|
| 734 |
|
| 735 ggp_search_remove(info->searches, form->seq); |
|
| 736 purple_debug_info("gg", "ggp_sr_close_cb(): Removed seq %u\n", |
|
| 737 form->seq); |
|
| 738 ggp_search_form_destroy(form); |
|
| 739 } |
|
| 740 |
|
| 741 /** |
|
| 742 * Translate a status' ID to a more user-friendly name. |
|
| 743 * |
|
| 744 * @param id The ID of the status. |
|
| 745 * |
|
| 746 * @return The user-friendly name of the status. |
|
| 747 */ |
|
| 748 static const char *ggp_status_by_id(unsigned int id) |
|
| 749 { |
|
| 750 const char *st; |
|
| 751 |
|
| 752 purple_debug_info("gg", "ggp_status_by_id: %d\n", id); |
|
| 753 switch (id) { |
|
| 754 case GG_STATUS_NOT_AVAIL: |
|
| 755 case GG_STATUS_NOT_AVAIL_DESCR: |
|
| 756 st = _("Offline"); |
|
| 757 break; |
|
| 758 case GG_STATUS_AVAIL: |
|
| 759 case GG_STATUS_AVAIL_DESCR: |
|
| 760 st = _("Available"); |
|
| 761 break; |
|
| 762 case GG_STATUS_FFC: |
|
| 763 case GG_STATUS_FFC_DESCR: |
|
| 764 return _("Chatty"); |
|
| 765 case GG_STATUS_DND: |
|
| 766 case GG_STATUS_DND_DESCR: |
|
| 767 return _("Do Not Disturb"); |
|
| 768 case GG_STATUS_BUSY: |
|
| 769 case GG_STATUS_BUSY_DESCR: |
|
| 770 st = _("Away"); |
|
| 771 break; |
|
| 772 default: |
|
| 773 st = _("Unknown"); |
|
| 774 break; |
|
| 775 } |
|
| 776 |
|
| 777 return st; |
|
| 778 } |
|
| 779 |
|
| 780 static void ggp_pubdir_handle_info(PurpleConnection *gc, gg_pubdir50_t req, |
|
| 781 GGPSearchForm *form) |
|
| 782 { |
|
| 783 PurpleNotifyUserInfo *user_info; |
|
| 784 PurpleBuddy *buddy; |
|
| 785 char *val, *who; |
|
| 786 |
|
| 787 user_info = purple_notify_user_info_new(); |
|
| 788 |
|
| 789 val = ggp_search_get_result(req, 0, GG_PUBDIR50_STATUS); |
|
| 790 /* XXX: Use of ggp_str_to_uin() is an ugly hack! */ |
|
| 791 purple_notify_user_info_add_pair(user_info, _("Status"), ggp_status_by_id(ggp_str_to_uin(val))); |
|
| 792 g_free(val); |
|
| 793 |
|
| 794 who = ggp_search_get_result(req, 0, GG_PUBDIR50_UIN); |
|
| 795 purple_notify_user_info_add_pair(user_info, _("UIN"), who); |
|
| 796 |
|
| 797 val = ggp_search_get_result(req, 0, GG_PUBDIR50_FIRSTNAME); |
|
| 798 purple_notify_user_info_add_pair(user_info, _("First Name"), val); |
|
| 799 g_free(val); |
|
| 800 |
|
| 801 val = ggp_search_get_result(req, 0, GG_PUBDIR50_NICKNAME); |
|
| 802 purple_notify_user_info_add_pair(user_info, _("Nickname"), val); |
|
| 803 g_free(val); |
|
| 804 |
|
| 805 val = ggp_search_get_result(req, 0, GG_PUBDIR50_CITY); |
|
| 806 purple_notify_user_info_add_pair(user_info, _("City"), val); |
|
| 807 g_free(val); |
|
| 808 |
|
| 809 val = ggp_search_get_result(req, 0, GG_PUBDIR50_BIRTHYEAR); |
|
| 810 if (strncmp(val, "0", 1)) { |
|
| 811 purple_notify_user_info_add_pair(user_info, _("Birth Year"), val); |
|
| 812 } |
|
| 813 g_free(val); |
|
| 814 |
|
| 815 /* |
|
| 816 * Include a status message, if exists and buddy is in the blist. |
|
| 817 */ |
|
| 818 buddy = purple_find_buddy(purple_connection_get_account(gc), who); |
|
| 819 if (NULL != buddy) { |
|
| 820 PurpleStatus *status; |
|
| 821 const char *msg; |
|
| 822 char *text; |
|
| 823 |
|
| 824 status = purple_presence_get_active_status(purple_buddy_get_presence(buddy)); |
|
| 825 msg = purple_status_get_attr_string(status, "message"); |
|
| 826 |
|
| 827 if (msg != NULL) { |
|
| 828 text = g_markup_escape_text(msg, -1); |
|
| 829 purple_notify_user_info_add_pair(user_info, _("Message"), text); |
|
| 830 g_free(text); |
|
| 831 } |
|
| 832 } |
|
| 833 |
|
| 834 purple_notify_userinfo(gc, who, user_info, ggp_sr_close_cb, form); |
|
| 835 g_free(who); |
|
| 836 purple_notify_user_info_destroy(user_info); |
|
| 837 } |
|
| 838 |
|
| 839 static void ggp_pubdir_handle_full(PurpleConnection *gc, gg_pubdir50_t req, |
|
| 840 GGPSearchForm *form) |
|
| 841 { |
|
| 842 PurpleNotifySearchResults *results; |
|
| 843 PurpleNotifySearchColumn *column; |
|
| 844 int res_count; |
|
| 845 int start; |
|
| 846 int i; |
|
| 847 |
|
| 848 g_return_if_fail(form != NULL); |
|
| 849 |
|
| 850 res_count = gg_pubdir50_count(req); |
|
| 851 res_count = (res_count > PUBDIR_RESULTS_MAX) ? PUBDIR_RESULTS_MAX : res_count; |
|
| 852 if (form->page_size == 0) |
|
| 853 form->page_size = res_count; |
|
| 854 |
|
| 855 results = purple_notify_searchresults_new(); |
|
| 856 |
|
| 857 if (results == NULL) { |
|
| 858 purple_debug_error("gg", "ggp_pubdir_reply_handler: " |
|
| 859 "Unable to display the search results.\n"); |
|
| 860 purple_notify_error(gc, NULL, |
|
| 861 _("Unable to display the search results."), |
|
| 862 NULL); |
|
| 863 if (form->window == NULL) |
|
| 864 ggp_sr_close_cb(form); |
|
| 865 return; |
|
| 866 } |
|
| 867 |
|
| 868 column = purple_notify_searchresults_column_new(_("UIN")); |
|
| 869 purple_notify_searchresults_column_add(results, column); |
|
| 870 |
|
| 871 column = purple_notify_searchresults_column_new(_("First Name")); |
|
| 872 purple_notify_searchresults_column_add(results, column); |
|
| 873 |
|
| 874 column = purple_notify_searchresults_column_new(_("Nickname")); |
|
| 875 purple_notify_searchresults_column_add(results, column); |
|
| 876 |
|
| 877 column = purple_notify_searchresults_column_new(_("City")); |
|
| 878 purple_notify_searchresults_column_add(results, column); |
|
| 879 |
|
| 880 column = purple_notify_searchresults_column_new(_("Birth Year")); |
|
| 881 purple_notify_searchresults_column_add(results, column); |
|
| 882 |
|
| 883 purple_debug_info("gg", "Going with %d entries\n", res_count); |
|
| 884 |
|
| 885 start = (int)ggp_str_to_uin(gg_pubdir50_get(req, 0, GG_PUBDIR50_START)); |
|
| 886 purple_debug_info("gg", "start = %d\n", start); |
|
| 887 |
|
| 888 for (i = 0; i < res_count; i++) { |
|
| 889 GList *row = NULL; |
|
| 890 char *birth = ggp_search_get_result(req, i, GG_PUBDIR50_BIRTHYEAR); |
|
| 891 |
|
| 892 /* TODO: Status will be displayed as an icon. */ |
|
| 893 /* row = g_list_append(row, ggp_search_get_result(req, i, GG_PUBDIR50_STATUS)); */ |
|
| 894 row = g_list_append(row, ggp_search_get_result(req, i, |
|
| 895 GG_PUBDIR50_UIN)); |
|
| 896 row = g_list_append(row, ggp_search_get_result(req, i, |
|
| 897 GG_PUBDIR50_FIRSTNAME)); |
|
| 898 row = g_list_append(row, ggp_search_get_result(req, i, |
|
| 899 GG_PUBDIR50_NICKNAME)); |
|
| 900 row = g_list_append(row, ggp_search_get_result(req, i, |
|
| 901 GG_PUBDIR50_CITY)); |
|
| 902 row = g_list_append(row, |
|
| 903 (birth && strncmp(birth, "0", 1)) ? birth : g_strdup("-")); |
|
| 904 |
|
| 905 purple_notify_searchresults_row_add(results, row); |
|
| 906 } |
|
| 907 |
|
| 908 purple_notify_searchresults_button_add(results, PURPLE_NOTIFY_BUTTON_CONTINUE, |
|
| 909 ggp_callback_show_next); |
|
| 910 purple_notify_searchresults_button_add(results, PURPLE_NOTIFY_BUTTON_ADD, |
|
| 911 ggp_callback_add_buddy); |
|
| 912 purple_notify_searchresults_button_add(results, PURPLE_NOTIFY_BUTTON_IM, |
|
| 913 ggp_callback_im); |
|
| 914 |
|
| 915 if (form->window == NULL) { |
|
| 916 void *h = purple_notify_searchresults(gc, |
|
| 917 _("Gadu-Gadu Public Directory"), |
|
| 918 _("Search results"), NULL, results, |
|
| 919 (PurpleNotifyCloseCallback)ggp_sr_close_cb, |
|
| 920 form); |
|
| 921 |
|
| 922 if (h == NULL) { |
|
| 923 purple_debug_error("gg", "ggp_pubdir_reply_handler: " |
|
| 924 "Unable to display the search results.\n"); |
|
| 925 purple_notify_error(gc, NULL, |
|
| 926 _("Unable to display the search results."), |
|
| 927 NULL); |
|
| 928 return; |
|
| 929 } |
|
| 930 |
|
| 931 form->window = h; |
|
| 932 } else { |
|
| 933 purple_notify_searchresults_new_rows(gc, results, form->window); |
|
| 934 } |
|
| 935 } |
|
| 936 |
|
| 937 static void ggp_pubdir_reply_handler(PurpleConnection *gc, gg_pubdir50_t req) |
|
| 938 { |
|
| 939 GGPInfo *info = gc->proto_data; |
|
| 940 GGPSearchForm *form; |
|
| 941 int res_count; |
|
| 942 guint32 seq; |
|
| 943 |
|
| 944 seq = gg_pubdir50_seq(req); |
|
| 945 form = ggp_search_get(info->searches, seq); |
|
| 946 purple_debug_info("gg", |
|
| 947 "ggp_pubdir_reply_handler(): seq %u --> form %p\n", seq, form); |
|
| 948 /* |
|
| 949 * this can happen when user will request more results |
|
| 950 * and close the results window before they arrive. |
|
| 951 */ |
|
| 952 g_return_if_fail(form != NULL); |
|
| 953 |
|
| 954 res_count = gg_pubdir50_count(req); |
|
| 955 if (res_count < 1) { |
|
| 956 purple_debug_info("gg", "GG_EVENT_PUBDIR50_SEARCH_REPLY: Nothing found\n"); |
|
| 957 purple_notify_error(gc, NULL, |
|
| 958 _("No matching users found"), |
|
| 959 _("There are no users matching your search criteria.")); |
|
| 960 if (form->window == NULL) |
|
| 961 ggp_sr_close_cb(form); |
|
| 962 return; |
|
| 963 } |
|
| 964 |
|
| 965 switch (form->search_type) { |
|
| 966 case GGP_SEARCH_TYPE_INFO: |
|
| 967 ggp_pubdir_handle_info(gc, req, form); |
|
| 968 break; |
|
| 969 case GGP_SEARCH_TYPE_FULL: |
|
| 970 ggp_pubdir_handle_full(gc, req, form); |
|
| 971 break; |
|
| 972 default: |
|
| 973 purple_debug_warning("gg", "Unknown search_type!\n"); |
|
| 974 break; |
|
| 975 } |
|
| 976 } |
|
| 977 |
|
| 978 static void ggp_recv_image_handler(PurpleConnection *gc, const struct gg_event *ev) |
|
| 979 { |
|
| 980 gint imgid = 0; |
|
| 981 GGPInfo *info = gc->proto_data; |
|
| 982 GList *entry = g_list_first(info->pending_richtext_messages); |
|
| 983 gchar *handlerid = g_strdup_printf("IMGID_HANDLER-%i", ev->event.image_reply.crc32); |
|
| 984 |
|
| 985 imgid = purple_imgstore_add_with_id( |
|
| 986 g_memdup2(ev->event.image_reply.image, ev->event.image_reply.size), |
|
| 987 ev->event.image_reply.size, |
|
| 988 ev->event.image_reply.filename); |
|
| 989 |
|
| 990 purple_debug_info("gg", "ggp_recv_image_handler: got image with crc32: %u\n", ev->event.image_reply.crc32); |
|
| 991 |
|
| 992 while(entry) { |
|
| 993 if (strstr((gchar *)entry->data, handlerid) != NULL) { |
|
| 994 gchar **split = g_strsplit((gchar *)entry->data, handlerid, 3); |
|
| 995 gchar *text = g_strdup_printf("%s%i%s", split[0], imgid, split[1]); |
|
| 996 purple_debug_info("gg", "ggp_recv_image_handler: found message matching crc32: %s\n", (gchar *)entry->data); |
|
| 997 g_strfreev(split); |
|
| 998 info->pending_richtext_messages = g_list_remove(info->pending_richtext_messages, entry->data); |
|
| 999 /* We don't have any more images to download */ |
|
| 1000 if (strstr(text, "<IMG ID=\"IMGID_HANDLER") == NULL) { |
|
| 1001 gchar *buf = g_strdup_printf("%lu", (unsigned long int)ev->event.image_reply.sender); |
|
| 1002 serv_got_im(gc, buf, text, PURPLE_MESSAGE_IMAGES, time(NULL)); |
|
| 1003 g_free(buf); |
|
| 1004 purple_debug_info("gg", "ggp_recv_image_handler: richtext message: %s\n", text); |
|
| 1005 g_free(text); |
|
| 1006 break; |
|
| 1007 } |
|
| 1008 info->pending_richtext_messages = g_list_append(info->pending_richtext_messages, text); |
|
| 1009 break; |
|
| 1010 } |
|
| 1011 entry = g_list_next(entry); |
|
| 1012 } |
|
| 1013 g_free(handlerid); |
|
| 1014 |
|
| 1015 return; |
|
| 1016 } |
|
| 1017 |
|
| 1018 |
|
| 1019 /** |
|
| 1020 * Dispatch a message received from a buddy. |
|
| 1021 * |
|
| 1022 * @param gc PurpleConnection. |
|
| 1023 * @param ev Gadu-Gadu event structure. |
|
| 1024 * |
|
| 1025 * Image receiving, some code borrowed from Kadu http://www.kadu.net |
|
| 1026 */ |
|
| 1027 static void ggp_recv_message_handler(PurpleConnection *gc, const struct gg_event *ev) |
|
| 1028 { |
|
| 1029 GGPInfo *info = gc->proto_data; |
|
| 1030 PurpleConversation *conv; |
|
| 1031 gchar *from; |
|
| 1032 gchar *msg; |
|
| 1033 gchar *tmp; |
|
| 1034 |
|
| 1035 if (ev->event.msg.message == NULL) |
|
| 1036 { |
|
| 1037 purple_debug_warning("gg", "ggp_recv_message_handler: NULL as message pointer\n"); |
|
| 1038 return; |
|
| 1039 } |
|
| 1040 |
|
| 1041 from = g_strdup_printf("%lu", (unsigned long int)ev->event.msg.sender); |
|
| 1042 |
|
| 1043 /* |
|
| 1044 tmp = charset_convert((const char *)ev->event.msg.message, |
|
| 1045 "CP1250", "UTF-8"); |
|
| 1046 */ |
|
| 1047 tmp = g_strdup_printf("%s", ev->event.msg.message); |
|
| 1048 purple_str_strip_char(tmp, '\r'); |
|
| 1049 msg = g_markup_escape_text(tmp, -1); |
|
| 1050 g_free(tmp); |
|
| 1051 |
|
| 1052 /* We got richtext message */ |
|
| 1053 if (ev->event.msg.formats_length) |
|
| 1054 { |
|
| 1055 gboolean got_image = FALSE, bold = FALSE, italic = FALSE, under = FALSE; |
|
| 1056 char *cformats = (char *)ev->event.msg.formats; |
|
| 1057 char *cformats_end = cformats + ev->event.msg.formats_length; |
|
| 1058 gint increased_len = 0; |
|
| 1059 struct gg_msg_richtext_format *actformat; |
|
| 1060 struct gg_msg_richtext_image *actimage; |
|
| 1061 GString *message = g_string_new(msg); |
|
| 1062 gchar *handlerid; |
|
| 1063 |
|
| 1064 purple_debug_info("gg", "ggp_recv_message_handler: richtext msg from (%s): %s %i formats\n", from, msg, ev->event.msg.formats_length); |
|
| 1065 |
|
| 1066 while (cformats < cformats_end) |
|
| 1067 { |
|
| 1068 gint byteoffset; |
|
| 1069 actformat = (struct gg_msg_richtext_format *)cformats; |
|
| 1070 cformats += sizeof(struct gg_msg_richtext_format); |
|
| 1071 byteoffset = g_utf8_offset_to_pointer(message->str, actformat->position + increased_len) - message->str; |
|
| 1072 |
|
| 1073 if(actformat->position == 0 && actformat->font == 0) { |
|
| 1074 purple_debug_warning("gg", "ggp_recv_message_handler: bogus formatting (inc: %i)\n", increased_len); |
|
| 1075 continue; |
|
| 1076 } |
|
| 1077 purple_debug_info("gg", "ggp_recv_message_handler: format at pos: %i, image:%i, bold:%i, italic: %i, under:%i (inc: %i)\n", |
|
| 1078 actformat->position, |
|
| 1079 (actformat->font & GG_FONT_IMAGE) != 0, |
|
| 1080 (actformat->font & GG_FONT_BOLD) != 0, |
|
| 1081 (actformat->font & GG_FONT_ITALIC) != 0, |
|
| 1082 (actformat->font & GG_FONT_UNDERLINE) != 0, |
|
| 1083 increased_len); |
|
| 1084 |
|
| 1085 if (actformat->font & GG_FONT_IMAGE) { |
|
| 1086 got_image = TRUE; |
|
| 1087 actimage = (struct gg_msg_richtext_image*)(cformats); |
|
| 1088 cformats += sizeof(struct gg_msg_richtext_image); |
|
| 1089 purple_debug_info("gg", "ggp_recv_message_handler: image received, size: %d, crc32: %i\n", actimage->size, actimage->crc32); |
|
| 1090 |
|
| 1091 /* Checking for errors, image size shouldn't be |
|
| 1092 * larger than 255.000 bytes */ |
|
| 1093 if (actimage->size > 255000) { |
|
| 1094 purple_debug_warning("gg", "ggp_recv_message_handler: received image large than 255 kb\n"); |
|
| 1095 continue; |
|
| 1096 } |
|
| 1097 |
|
| 1098 gg_image_request(info->session, ev->event.msg.sender, |
|
| 1099 actimage->size, actimage->crc32); |
|
| 1100 |
|
| 1101 handlerid = g_strdup_printf("<IMG ID=\"IMGID_HANDLER-%i\">", actimage->crc32); |
|
| 1102 g_string_insert(message, byteoffset, handlerid); |
|
| 1103 increased_len += strlen(handlerid); |
|
| 1104 g_free(handlerid); |
|
| 1105 continue; |
|
| 1106 } |
|
| 1107 |
|
| 1108 if (actformat->font & GG_FONT_BOLD) { |
|
| 1109 if (bold == FALSE) { |
|
| 1110 g_string_insert(message, byteoffset, "<b>"); |
|
| 1111 increased_len += 3; |
|
| 1112 bold = TRUE; |
|
| 1113 } |
|
| 1114 } else if (bold) { |
|
| 1115 g_string_insert(message, byteoffset, "</b>"); |
|
| 1116 increased_len += 4; |
|
| 1117 bold = FALSE; |
|
| 1118 } |
|
| 1119 |
|
| 1120 if (actformat->font & GG_FONT_ITALIC) { |
|
| 1121 if (italic == FALSE) { |
|
| 1122 g_string_insert(message, byteoffset, "<i>"); |
|
| 1123 increased_len += 3; |
|
| 1124 italic = TRUE; |
|
| 1125 } |
|
| 1126 } else if (italic) { |
|
| 1127 g_string_insert(message, byteoffset, "</i>"); |
|
| 1128 increased_len += 4; |
|
| 1129 italic = FALSE; |
|
| 1130 } |
|
| 1131 |
|
| 1132 if (actformat->font & GG_FONT_UNDERLINE) { |
|
| 1133 if (under == FALSE) { |
|
| 1134 g_string_insert(message, byteoffset, "<u>"); |
|
| 1135 increased_len += 3; |
|
| 1136 under = TRUE; |
|
| 1137 } |
|
| 1138 } else if (under) { |
|
| 1139 g_string_insert(message, byteoffset, "</u>"); |
|
| 1140 increased_len += 4; |
|
| 1141 under = FALSE; |
|
| 1142 } |
|
| 1143 |
|
| 1144 if (actformat->font & GG_FONT_COLOR) { |
|
| 1145 cformats += sizeof(struct gg_msg_richtext_color); |
|
| 1146 } |
|
| 1147 } |
|
| 1148 |
|
| 1149 msg = g_string_free(message, FALSE); |
|
| 1150 |
|
| 1151 if (got_image) { |
|
| 1152 info->pending_richtext_messages = g_list_append(info->pending_richtext_messages, msg); |
|
| 1153 return; |
|
| 1154 } |
|
| 1155 } |
|
| 1156 |
|
| 1157 purple_debug_info("gg", "ggp_recv_message_handler: msg from (%s): %s (class = %d; rcpt_count = %d)\n", |
|
| 1158 from, msg, ev->event.msg.msgclass, |
|
| 1159 ev->event.msg.recipients_count); |
|
| 1160 |
|
| 1161 if (ev->event.msg.recipients_count == 0) { |
|
| 1162 serv_got_im(gc, from, msg, 0, ev->event.msg.time); |
|
| 1163 } else { |
|
| 1164 const char *chat_name; |
|
| 1165 int chat_id; |
|
| 1166 char *buddy_name; |
|
| 1167 |
|
| 1168 chat_name = ggp_confer_find_by_participants(gc, |
|
| 1169 ev->event.msg.recipients, |
|
| 1170 ev->event.msg.recipients_count); |
|
| 1171 |
|
| 1172 if (chat_name == NULL) { |
|
| 1173 chat_name = ggp_confer_add_new(gc, NULL); |
|
| 1174 serv_got_joined_chat(gc, info->chats_count, chat_name); |
|
| 1175 |
|
| 1176 ggp_confer_participants_add_uin(gc, chat_name, |
|
| 1177 ev->event.msg.sender); |
|
| 1178 |
|
| 1179 ggp_confer_participants_add(gc, chat_name, |
|
| 1180 ev->event.msg.recipients, |
|
| 1181 ev->event.msg.recipients_count); |
|
| 1182 } |
|
| 1183 conv = ggp_confer_find_by_name(gc, chat_name); |
|
| 1184 chat_id = purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)); |
|
| 1185 |
|
| 1186 buddy_name = ggp_buddy_get_name(gc, ev->event.msg.sender); |
|
| 1187 serv_got_chat_in(gc, chat_id, buddy_name, |
|
| 1188 PURPLE_MESSAGE_RECV, msg, ev->event.msg.time); |
|
| 1189 g_free(buddy_name); |
|
| 1190 } |
|
| 1191 g_free(msg); |
|
| 1192 g_free(from); |
|
| 1193 } |
|
| 1194 |
|
| 1195 static void ggp_send_image_handler(PurpleConnection *gc, const struct gg_event *ev) |
|
| 1196 { |
|
| 1197 GGPInfo *info = gc->proto_data; |
|
| 1198 PurpleStoredImage *image; |
|
| 1199 gint imgid = GPOINTER_TO_INT(g_hash_table_lookup(info->pending_images, GINT_TO_POINTER(ev->event.image_request.crc32))); |
|
| 1200 |
|
| 1201 purple_debug_info("gg", "ggp_send_image_handler: image request received, crc32: %u, imgid: %d\n", ev->event.image_request.crc32, imgid); |
|
| 1202 |
|
| 1203 if(imgid) |
|
| 1204 { |
|
| 1205 if((image = purple_imgstore_find_by_id(imgid))) { |
|
| 1206 gint image_size = purple_imgstore_get_size(image); |
|
| 1207 gconstpointer image_bin = purple_imgstore_get_data(image); |
|
| 1208 const char *image_filename = purple_imgstore_get_filename(image); |
|
| 1209 |
|
| 1210 purple_debug_info("gg", "ggp_send_image_handler: sending image imgid: %i, crc: %u\n", imgid, ev->event.image_request.crc32); |
|
| 1211 gg_image_reply(info->session, (unsigned long int)ev->event.image_request.sender, image_filename, image_bin, image_size); |
|
| 1212 purple_imgstore_unref(image); |
|
| 1213 } else { |
|
| 1214 purple_debug_error("gg", "ggp_send_image_handler: image imgid: %i, crc: %u in hash but not found in imgstore!\n", imgid, ev->event.image_request.crc32); |
|
| 1215 } |
|
| 1216 g_hash_table_remove(info->pending_images, GINT_TO_POINTER(ev->event.image_request.crc32)); |
|
| 1217 } |
|
| 1218 } |
|
| 1219 |
|
| 1220 static void ggp_typing_notification_handler(PurpleConnection *gc, uin_t uin, int length) { |
|
| 1221 gchar *from; |
|
| 1222 |
|
| 1223 from = g_strdup_printf("%u", uin); |
|
| 1224 if (length) |
|
| 1225 serv_got_typing(gc, from, 0, PURPLE_TYPING); |
|
| 1226 else |
|
| 1227 serv_got_typing_stopped(gc, from); |
|
| 1228 g_free(from); |
|
| 1229 } |
|
| 1230 |
|
| 1231 /** |
|
| 1232 * Handling of XML events. |
|
| 1233 * |
|
| 1234 * @param gc PurpleConnection. |
|
| 1235 * @param data Raw XML contents. |
|
| 1236 * |
|
| 1237 * @see http://toxygen.net/libgadu/protocol/#ch1.13 |
|
| 1238 */ |
|
| 1239 static void ggp_xml_event_handler(PurpleConnection *gc, char *data) |
|
| 1240 { |
|
| 1241 xmlnode *xml = NULL; |
|
| 1242 xmlnode *xmlnode_next_event; |
|
| 1243 |
|
| 1244 xml = xmlnode_from_str(data, -1); |
|
| 1245 if (xml == NULL) |
|
| 1246 goto out; |
|
| 1247 |
|
| 1248 xmlnode_next_event = xmlnode_get_child(xml, "event"); |
|
| 1249 while (xmlnode_next_event != NULL) |
|
| 1250 { |
|
| 1251 xmlnode *xmlnode_current_event = xmlnode_next_event; |
|
| 1252 |
|
| 1253 xmlnode *xmlnode_type; |
|
| 1254 char *event_type_raw; |
|
| 1255 int event_type = 0; |
|
| 1256 |
|
| 1257 xmlnode *xmlnode_sender; |
|
| 1258 char *event_sender_raw; |
|
| 1259 uin_t event_sender = 0; |
|
| 1260 |
|
| 1261 xmlnode_next_event = xmlnode_get_next_twin(xmlnode_next_event); |
|
| 1262 |
|
| 1263 xmlnode_type = xmlnode_get_child(xmlnode_current_event, "type"); |
|
| 1264 if (xmlnode_type == NULL) |
|
| 1265 continue; |
|
| 1266 event_type_raw = xmlnode_get_data(xmlnode_type); |
|
| 1267 if (event_type_raw != NULL) |
|
| 1268 event_type = atoi(event_type_raw); |
|
| 1269 g_free(event_type_raw); |
|
| 1270 |
|
| 1271 xmlnode_sender = xmlnode_get_child(xmlnode_current_event, "sender"); |
|
| 1272 if (xmlnode_sender != NULL) |
|
| 1273 { |
|
| 1274 event_sender_raw = xmlnode_get_data(xmlnode_sender); |
|
| 1275 if (event_sender_raw != NULL) |
|
| 1276 event_sender = ggp_str_to_uin(event_sender_raw); |
|
| 1277 g_free(event_sender_raw); |
|
| 1278 } |
|
| 1279 |
|
| 1280 switch (event_type) |
|
| 1281 { |
|
| 1282 case 28: /* avatar update */ |
|
| 1283 purple_debug_info("gg", |
|
| 1284 "ggp_xml_event_handler: avatar updated (uid: %u)\n", |
|
| 1285 event_sender); |
|
| 1286 ggp_update_buddy_avatar(gc, event_sender); |
|
| 1287 break; |
|
| 1288 default: |
|
| 1289 purple_debug_error("gg", |
|
| 1290 "ggp_xml_event_handler: unsupported event type=%d from=%u\n", |
|
| 1291 event_type, event_sender); |
|
| 1292 } |
|
| 1293 } |
|
| 1294 |
|
| 1295 out: |
|
| 1296 if (xml) |
|
| 1297 xmlnode_free(xml); |
|
| 1298 } |
|
| 1299 |
|
| 1300 static void ggp_callback_recv(gpointer _gc, gint fd, PurpleInputCondition cond) |
|
| 1301 { |
|
| 1302 PurpleConnection *gc = _gc; |
|
| 1303 GGPInfo *info = gc->proto_data; |
|
| 1304 struct gg_event *ev; |
|
| 1305 int i; |
|
| 1306 |
|
| 1307 if (!(ev = gg_watch_fd(info->session))) { |
|
| 1308 purple_debug_error("gg", |
|
| 1309 "ggp_callback_recv: gg_watch_fd failed -- CRITICAL!\n"); |
|
| 1310 purple_connection_error_reason (gc, |
|
| 1311 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, |
|
| 1312 _("Unable to read from socket")); |
|
| 1313 return; |
|
| 1314 } |
|
| 1315 |
|
| 1316 purple_input_remove(gc->inpa); |
|
| 1317 gc->inpa = purple_input_add(info->session->fd, |
|
| 1318 ggp_tcpsocket_inputcond_gg_to_purple(info->session->check), |
|
| 1319 ggp_callback_recv, gc); |
|
| 1320 |
|
| 1321 switch (ev->type) { |
|
| 1322 case GG_EVENT_NONE: |
|
| 1323 /* Nothing happened. */ |
|
| 1324 break; |
|
| 1325 case GG_EVENT_MSG: |
|
| 1326 ggp_recv_message_handler(gc, ev); |
|
| 1327 break; |
|
| 1328 case GG_EVENT_ACK: |
|
| 1329 /* Changing %u to %i fixes compiler warning */ |
|
| 1330 purple_debug_info("gg", |
|
| 1331 "ggp_callback_recv: message sent to: %i, delivery status=%d, seq=%d\n", |
|
| 1332 ev->event.ack.recipient, ev->event.ack.status, |
|
| 1333 ev->event.ack.seq); |
|
| 1334 break; |
|
| 1335 case GG_EVENT_IMAGE_REPLY: |
|
| 1336 ggp_recv_image_handler(gc, ev); |
|
| 1337 break; |
|
| 1338 case GG_EVENT_IMAGE_REQUEST: |
|
| 1339 ggp_send_image_handler(gc, ev); |
|
| 1340 break; |
|
| 1341 case GG_EVENT_NOTIFY: |
|
| 1342 case GG_EVENT_NOTIFY_DESCR: |
|
| 1343 { |
|
| 1344 struct gg_notify_reply *n; |
|
| 1345 char *descr; |
|
| 1346 |
|
| 1347 purple_debug_info("gg", "notify_pre: (%d) status: %d\n", |
|
| 1348 ev->event.notify->uin, |
|
| 1349 GG_S(ev->event.notify->status)); |
|
| 1350 |
|
| 1351 n = (ev->type == GG_EVENT_NOTIFY) ? ev->event.notify |
|
| 1352 : ev->event.notify_descr.notify; |
|
| 1353 |
|
| 1354 for (; n->uin; n++) { |
|
| 1355 descr = (ev->type == GG_EVENT_NOTIFY) ? NULL |
|
| 1356 : ev->event.notify_descr.descr; |
|
| 1357 |
|
| 1358 purple_debug_info("gg", |
|
| 1359 "notify: (%d) status: %d; descr: %s\n", |
|
| 1360 n->uin, GG_S(n->status), descr ? descr : "(null)"); |
|
| 1361 |
|
| 1362 ggp_generic_status_handler(gc, |
|
| 1363 n->uin, GG_S(n->status), descr); |
|
| 1364 } |
|
| 1365 } |
|
| 1366 break; |
|
| 1367 case GG_EVENT_NOTIFY60: |
|
| 1368 for (i = 0; ev->event.notify60[i].uin; i++) { |
|
| 1369 purple_debug_info("gg", |
|
| 1370 "notify60: (%d) status=%d; version=%d; descr=%s\n", |
|
| 1371 ev->event.notify60[i].uin, |
|
| 1372 GG_S(ev->event.notify60[i].status), |
|
| 1373 ev->event.notify60[i].version, |
|
| 1374 ev->event.notify60[i].descr ? ev->event.notify60[i].descr : "(null)"); |
|
| 1375 |
|
| 1376 ggp_generic_status_handler(gc, ev->event.notify60[i].uin, |
|
| 1377 GG_S(ev->event.notify60[i].status), |
|
| 1378 ev->event.notify60[i].descr); |
|
| 1379 } |
|
| 1380 break; |
|
| 1381 case GG_EVENT_STATUS: |
|
| 1382 purple_debug_info("gg", "status: (%d) status=%d; descr=%s\n", |
|
| 1383 ev->event.status.uin, GG_S(ev->event.status.status), |
|
| 1384 ev->event.status.descr ? ev->event.status.descr : "(null)"); |
|
| 1385 |
|
| 1386 ggp_generic_status_handler(gc, ev->event.status.uin, |
|
| 1387 GG_S(ev->event.status.status), ev->event.status.descr); |
|
| 1388 break; |
|
| 1389 case GG_EVENT_STATUS60: |
|
| 1390 purple_debug_info("gg", |
|
| 1391 "status60: (%d) status=%d; version=%d; descr=%s\n", |
|
| 1392 ev->event.status60.uin, GG_S(ev->event.status60.status), |
|
| 1393 ev->event.status60.version, |
|
| 1394 ev->event.status60.descr ? ev->event.status60.descr : "(null)"); |
|
| 1395 |
|
| 1396 ggp_generic_status_handler(gc, ev->event.status60.uin, |
|
| 1397 GG_S(ev->event.status60.status), ev->event.status60.descr); |
|
| 1398 break; |
|
| 1399 case GG_EVENT_PUBDIR50_SEARCH_REPLY: |
|
| 1400 ggp_pubdir_reply_handler(gc, ev->event.pubdir50); |
|
| 1401 break; |
|
| 1402 case GG_EVENT_TYPING_NOTIFICATION: |
|
| 1403 ggp_typing_notification_handler(gc, ev->event.typing_notification.uin, |
|
| 1404 ev->event.typing_notification.length); |
|
| 1405 break; |
|
| 1406 case GG_EVENT_XML_EVENT: |
|
| 1407 purple_debug_info("gg", "GG_EVENT_XML_EVENT\n"); |
|
| 1408 ggp_xml_event_handler(gc, ev->event.xml_event.data); |
|
| 1409 break; |
|
| 1410 default: |
|
| 1411 purple_debug_error("gg", |
|
| 1412 "unsupported event type=%d\n", ev->type); |
|
| 1413 break; |
|
| 1414 } |
|
| 1415 |
|
| 1416 gg_free_event(ev); |
|
| 1417 } |
|
| 1418 |
|
| 1419 static void ggp_async_login_handler(gpointer _gc, gint fd, PurpleInputCondition cond) |
|
| 1420 { |
|
| 1421 PurpleConnection *gc = _gc; |
|
| 1422 GGPInfo *info; |
|
| 1423 struct gg_event *ev; |
|
| 1424 |
|
| 1425 g_return_if_fail(PURPLE_CONNECTION_IS_VALID(gc)); |
|
| 1426 |
|
| 1427 info = gc->proto_data; |
|
| 1428 |
|
| 1429 purple_debug_info("gg", "login_handler: session: check = %d; state = %d;\n", |
|
| 1430 info->session->check, info->session->state); |
|
| 1431 |
|
| 1432 switch (info->session->state) { |
|
| 1433 case GG_STATE_RESOLVING: |
|
| 1434 purple_debug_info("gg", "GG_STATE_RESOLVING\n"); |
|
| 1435 break; |
|
| 1436 case GG_STATE_RESOLVING_GG: |
|
| 1437 purple_debug_info("gg", "GG_STATE_RESOLVING_GG\n"); |
|
| 1438 break; |
|
| 1439 case GG_STATE_CONNECTING_HUB: |
|
| 1440 purple_debug_info("gg", "GG_STATE_CONNECTING_HUB\n"); |
|
| 1441 break; |
|
| 1442 case GG_STATE_READING_DATA: |
|
| 1443 purple_debug_info("gg", "GG_STATE_READING_DATA\n"); |
|
| 1444 break; |
|
| 1445 case GG_STATE_CONNECTING_GG: |
|
| 1446 purple_debug_info("gg", "GG_STATE_CONNECTING_GG\n"); |
|
| 1447 break; |
|
| 1448 case GG_STATE_READING_KEY: |
|
| 1449 purple_debug_info("gg", "GG_STATE_READING_KEY\n"); |
|
| 1450 break; |
|
| 1451 case GG_STATE_READING_REPLY: |
|
| 1452 purple_debug_info("gg", "GG_STATE_READING_REPLY\n"); |
|
| 1453 break; |
|
| 1454 case GG_STATE_TLS_NEGOTIATION: |
|
| 1455 purple_debug_info("gg", "GG_STATE_TLS_NEGOTIATION\n"); |
|
| 1456 break; |
|
| 1457 default: |
|
| 1458 purple_debug_error("gg", "unknown state = %d\n", |
|
| 1459 info->session->state); |
|
| 1460 break; |
|
| 1461 } |
|
| 1462 |
|
| 1463 if (!(ev = gg_watch_fd(info->session))) { |
|
| 1464 purple_debug_error("gg", "login_handler: gg_watch_fd failed!\n"); |
|
| 1465 purple_connection_error_reason (gc, |
|
| 1466 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, |
|
| 1467 _("Unable to read from socket")); |
|
| 1468 return; |
|
| 1469 } |
|
| 1470 purple_debug_info("gg", "login_handler: session->fd = %d\n", info->session->fd); |
|
| 1471 purple_debug_info("gg", "login_handler: session: check = %d; state = %d;\n", |
|
| 1472 info->session->check, info->session->state); |
|
| 1473 |
|
| 1474 purple_input_remove(gc->inpa); |
|
| 1475 |
|
| 1476 /** XXX I think that this shouldn't be done if ev->type is GG_EVENT_CONN_FAILED or GG_EVENT_CONN_SUCCESS -datallah */ |
|
| 1477 if (info->session->fd >= 0) |
|
| 1478 gc->inpa = purple_input_add(info->session->fd, |
|
| 1479 ggp_tcpsocket_inputcond_gg_to_purple(info->session->check), |
|
| 1480 ggp_async_login_handler, gc); |
|
| 1481 |
|
| 1482 switch (ev->type) { |
|
| 1483 case GG_EVENT_NONE: |
|
| 1484 /* Nothing happened. */ |
|
| 1485 purple_debug_info("gg", "GG_EVENT_NONE\n"); |
|
| 1486 break; |
|
| 1487 case GG_EVENT_CONN_SUCCESS: |
|
| 1488 { |
|
| 1489 purple_debug_info("gg", "GG_EVENT_CONN_SUCCESS\n"); |
|
| 1490 purple_input_remove(gc->inpa); |
|
| 1491 gc->inpa = purple_input_add(info->session->fd, |
|
| 1492 ggp_tcpsocket_inputcond_gg_to_purple(info->session->check), |
|
| 1493 ggp_callback_recv, gc); |
|
| 1494 |
|
| 1495 ggp_buddylist_send(gc); |
|
| 1496 purple_connection_update_progress(gc, _("Connected"), 1, 2); |
|
| 1497 purple_connection_set_state(gc, PURPLE_CONNECTED); |
|
| 1498 } |
|
| 1499 break; |
|
| 1500 case GG_EVENT_CONN_FAILED: |
|
| 1501 purple_input_remove(gc->inpa); |
|
| 1502 gc->inpa = 0; |
|
| 1503 purple_connection_error_reason (gc, |
|
| 1504 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, |
|
| 1505 _("Connection failed")); |
|
| 1506 break; |
|
| 1507 case GG_EVENT_MSG: |
|
| 1508 if (ev->event.msg.sender == 0) |
|
| 1509 /* system messages are mostly ads */ |
|
| 1510 purple_debug_info("gg", "System message:\n%s\n", |
|
| 1511 ev->event.msg.message); |
|
| 1512 else |
|
| 1513 purple_debug_warning("gg", "GG_EVENT_MSG: message from user %u " |
|
| 1514 "unexpected while connecting:\n%s\n", |
|
| 1515 ev->event.msg.sender, |
|
| 1516 ev->event.msg.message); |
|
| 1517 break; |
|
| 1518 default: |
|
| 1519 purple_debug_error("gg", "strange event: %d\n", ev->type); |
|
| 1520 break; |
|
| 1521 } |
|
| 1522 |
|
| 1523 gg_free_event(ev); |
|
| 1524 } |
|
| 1525 |
|
| 1526 /* ---------------------------------------------------------------------- */ |
|
| 1527 /* ----- PurplePluginProtocolInfo ----------------------------------------- */ |
|
| 1528 /* ---------------------------------------------------------------------- */ |
|
| 1529 |
|
| 1530 static const char *ggp_list_icon(PurpleAccount *account, PurpleBuddy *buddy) |
|
| 1531 { |
|
| 1532 return "gadu-gadu"; |
|
| 1533 } |
|
| 1534 |
|
| 1535 static char *ggp_status_text(PurpleBuddy *b) |
|
| 1536 { |
|
| 1537 PurpleStatus *status; |
|
| 1538 const char *msg; |
|
| 1539 char *text; |
|
| 1540 char *tmp; |
|
| 1541 |
|
| 1542 status = purple_presence_get_active_status( |
|
| 1543 purple_buddy_get_presence(b)); |
|
| 1544 msg = purple_status_get_attr_string(status, "message"); |
|
| 1545 |
|
| 1546 if (msg == NULL) |
|
| 1547 return NULL; |
|
| 1548 |
|
| 1549 tmp = purple_markup_strip_html(msg); |
|
| 1550 text = g_markup_escape_text(tmp, -1); |
|
| 1551 g_free(tmp); |
|
| 1552 |
|
| 1553 return text; |
|
| 1554 } |
|
| 1555 |
|
| 1556 static void ggp_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full) |
|
| 1557 { |
|
| 1558 PurpleStatus *status; |
|
| 1559 char *text, *tmp; |
|
| 1560 const char *msg, *name, *alias; |
|
| 1561 |
|
| 1562 g_return_if_fail(b != NULL); |
|
| 1563 |
|
| 1564 status = purple_presence_get_active_status(purple_buddy_get_presence(b)); |
|
| 1565 msg = purple_status_get_attr_string(status, "message"); |
|
| 1566 name = purple_status_get_name(status); |
|
| 1567 alias = purple_buddy_get_alias(b); |
|
| 1568 |
|
| 1569 purple_notify_user_info_add_pair (user_info, _("Alias"), alias); |
|
| 1570 |
|
| 1571 if (msg != NULL) { |
|
| 1572 text = g_markup_escape_text(msg, -1); |
|
| 1573 if (PURPLE_BUDDY_IS_ONLINE(b)) { |
|
| 1574 tmp = g_strdup_printf("%s: %s", name, text); |
|
| 1575 purple_notify_user_info_add_pair(user_info, _("Status"), tmp); |
|
| 1576 g_free(tmp); |
|
| 1577 } else { |
|
| 1578 purple_notify_user_info_add_pair(user_info, _("Message"), text); |
|
| 1579 } |
|
| 1580 g_free(text); |
|
| 1581 /* We don't want to duplicate 'Status: Offline'. */ |
|
| 1582 } else if (PURPLE_BUDDY_IS_ONLINE(b)) { |
|
| 1583 purple_notify_user_info_add_pair(user_info, _("Status"), name); |
|
| 1584 } |
|
| 1585 } |
|
| 1586 |
|
| 1587 static GList *ggp_status_types(PurpleAccount *account) |
|
| 1588 { |
|
| 1589 PurpleStatusType *type; |
|
| 1590 GList *types = NULL; |
|
| 1591 |
|
| 1592 type = purple_status_type_new_with_attrs( |
|
| 1593 PURPLE_STATUS_AVAILABLE, NULL, NULL, TRUE, TRUE, FALSE, |
|
| 1594 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), |
|
| 1595 NULL); |
|
| 1596 types = g_list_append(types, type); |
|
| 1597 |
|
| 1598 /* |
|
| 1599 * Without this selecting Invisible as own status doesn't |
|
| 1600 * work. It's not used and not needed to show status of buddies. |
|
| 1601 */ |
|
| 1602 type = purple_status_type_new_with_attrs( |
|
| 1603 PURPLE_STATUS_INVISIBLE, NULL, NULL, TRUE, TRUE, FALSE, |
|
| 1604 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), |
|
| 1605 NULL); |
|
| 1606 types = g_list_append(types, type); |
|
| 1607 |
|
| 1608 type = purple_status_type_new_with_attrs( |
|
| 1609 PURPLE_STATUS_AWAY, NULL, NULL, TRUE, TRUE, FALSE, |
|
| 1610 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), |
|
| 1611 NULL); |
|
| 1612 types = g_list_append(types, type); |
|
| 1613 |
|
| 1614 /* |
|
| 1615 * New statuses for GG 8.0 like PoGGadaj ze mna (not yet because |
|
| 1616 * libpurple can't support Chatty status) and Nie przeszkadzac |
|
| 1617 */ |
|
| 1618 type = purple_status_type_new_with_attrs( |
|
| 1619 PURPLE_STATUS_UNAVAILABLE, NULL, NULL, TRUE, TRUE, FALSE, |
|
| 1620 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), |
|
| 1621 NULL); |
|
| 1622 types = g_list_append(types, type); |
|
| 1623 |
|
| 1624 /* |
|
| 1625 * This status is necessary to display guys who are blocking *us*. |
|
| 1626 */ |
|
| 1627 type = purple_status_type_new_with_attrs( |
|
| 1628 PURPLE_STATUS_INVISIBLE, "blocked", _("Blocked"), TRUE, FALSE, FALSE, |
|
| 1629 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), NULL); |
|
| 1630 types = g_list_append(types, type); |
|
| 1631 |
|
| 1632 type = purple_status_type_new_with_attrs( |
|
| 1633 PURPLE_STATUS_OFFLINE, NULL, NULL, TRUE, TRUE, FALSE, |
|
| 1634 "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), |
|
| 1635 NULL); |
|
| 1636 types = g_list_append(types, type); |
|
| 1637 |
|
| 1638 return types; |
|
| 1639 } |
|
| 1640 |
|
| 1641 static GList *ggp_blist_node_menu(PurpleBlistNode *node) |
|
| 1642 { |
|
| 1643 PurpleMenuAction *act; |
|
| 1644 GList *m = NULL; |
|
| 1645 PurpleAccount *account; |
|
| 1646 GGPInfo *info; |
|
| 1647 |
|
| 1648 if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) |
|
| 1649 return NULL; |
|
| 1650 |
|
| 1651 account = purple_buddy_get_account((PurpleBuddy *) node); |
|
| 1652 info = purple_account_get_connection(account)->proto_data; |
|
| 1653 if (info->chats) { |
|
| 1654 act = purple_menu_action_new(_("Add to chat"), |
|
| 1655 PURPLE_CALLBACK(ggp_bmenu_add_to_chat), |
|
| 1656 NULL, NULL); |
|
| 1657 m = g_list_append(m, act); |
|
| 1658 } |
|
| 1659 |
|
| 1660 return m; |
|
| 1661 } |
|
| 1662 |
|
| 1663 static GList *ggp_chat_info(PurpleConnection *gc) |
|
| 1664 { |
|
| 1665 GList *m = NULL; |
|
| 1666 struct proto_chat_entry *pce; |
|
| 1667 |
|
| 1668 pce = g_new0(struct proto_chat_entry, 1); |
|
| 1669 pce->label = _("Chat _name:"); |
|
| 1670 pce->identifier = "name"; |
|
| 1671 pce->required = TRUE; |
|
| 1672 m = g_list_append(m, pce); |
|
| 1673 |
|
| 1674 return m; |
|
| 1675 } |
|
| 1676 |
|
| 1677 static void ggp_login_to(PurpleAccount *account, uint32_t server) |
|
| 1678 { |
|
| 1679 PurpleConnection *gc; |
|
| 1680 PurplePresence *presence; |
|
| 1681 PurpleStatus *status; |
|
| 1682 struct gg_login_params *glp; |
|
| 1683 GGPInfo *info; |
|
| 1684 const gchar *encryption_type; |
|
| 1685 |
|
| 1686 if (ggp_setup_proxy(account) == -1) |
|
| 1687 return; |
|
| 1688 |
|
| 1689 gc = purple_account_get_connection(account); |
|
| 1690 glp = g_new0(struct gg_login_params, 1); |
|
| 1691 info = gc->proto_data; |
|
| 1692 g_return_if_fail(info); |
|
| 1693 |
|
| 1694 /* Probably this should be moved to *_new() function. */ |
|
| 1695 info->session = NULL; |
|
| 1696 info->chats = NULL; |
|
| 1697 info->chats_count = 0; |
|
| 1698 info->token = NULL; |
|
| 1699 info->searches = ggp_search_new(); |
|
| 1700 info->pending_richtext_messages = NULL; |
|
| 1701 info->pending_images = g_hash_table_new(g_direct_hash, g_direct_equal); |
|
| 1702 info->status_broadcasting = purple_account_get_bool(account, "status_broadcasting", TRUE); |
|
| 1703 |
|
| 1704 glp->uin = ggp_get_uin(account); |
|
| 1705 glp->password = (char *)purple_account_get_password(account); |
|
| 1706 glp->image_size = 255; |
|
| 1707 |
|
| 1708 presence = purple_account_get_presence(account); |
|
| 1709 status = purple_presence_get_active_status(presence); |
|
| 1710 |
|
| 1711 glp->encoding = GG_ENCODING_UTF8; |
|
| 1712 glp->protocol_features = (GG_FEATURE_STATUS80|GG_FEATURE_DND_FFC |
|
| 1713 |GG_FEATURE_TYPING_NOTIFICATION); |
|
| 1714 |
|
| 1715 glp->async = 1; |
|
| 1716 glp->status = ggp_to_gg_status(status, &glp->status_descr); |
|
| 1717 |
|
| 1718 encryption_type = purple_account_get_string(account, "encryption", "none"); |
|
| 1719 purple_debug_info("gg", "Requested encryption type: %s\n", encryption_type); |
|
| 1720 if (purple_strequal(encryption_type, "opportunistic_tls")) |
|
| 1721 glp->tls = 1; |
|
| 1722 else |
|
| 1723 glp->tls = 0; |
|
| 1724 purple_debug_info("gg", "TLS enabled: %d\n", glp->tls); |
|
| 1725 |
|
| 1726 if (!info->status_broadcasting) |
|
| 1727 glp->status = glp->status|GG_STATUS_FRIENDS_MASK; |
|
| 1728 glp->server_addr = server; |
|
| 1729 |
|
| 1730 info->session = gg_login(glp); |
|
| 1731 g_free(glp); |
|
| 1732 |
|
| 1733 purple_connection_update_progress(gc, _("Connecting"), 0, 2); |
|
| 1734 if (info->session == NULL) { |
|
| 1735 purple_connection_error_reason (gc, |
|
| 1736 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, |
|
| 1737 _("Connection failed")); |
|
| 1738 return; |
|
| 1739 } |
|
| 1740 gc->inpa = purple_input_add(info->session->fd, |
|
| 1741 ggp_tcpsocket_inputcond_gg_to_purple(info->session->check), |
|
| 1742 ggp_async_login_handler, gc); |
|
| 1743 } |
|
| 1744 |
|
| 1745 static void |
|
| 1746 ggp_login_resolved(GSList *hosts, gpointer _account, const char *error_message) |
|
| 1747 { |
|
| 1748 PurpleAccount *account = _account; |
|
| 1749 PurpleConnection *gc; |
|
| 1750 GGPInfo *info; |
|
| 1751 uint32_t server_addr = 0; |
|
| 1752 |
|
| 1753 gc = purple_account_get_connection(account); |
|
| 1754 info = gc->proto_data; |
|
| 1755 g_return_if_fail(info); |
|
| 1756 info->dns_query = NULL; |
|
| 1757 |
|
| 1758 while (hosts && (hosts = g_slist_delete_link(hosts, hosts))) { |
|
| 1759 struct sockaddr *addr = hosts->data; |
|
| 1760 |
|
| 1761 if (addr->sa_family == AF_INET && server_addr == 0) { |
|
| 1762 struct sockaddr_in *addrv4 = (struct sockaddr_in *)addr; |
|
| 1763 |
|
| 1764 server_addr = addrv4->sin_addr.s_addr; |
|
| 1765 } |
|
| 1766 |
|
| 1767 g_free(hosts->data); |
|
| 1768 hosts = g_slist_delete_link(hosts, hosts); |
|
| 1769 } |
|
| 1770 |
|
| 1771 if (server_addr == 0) { |
|
| 1772 gchar *tmp = g_strdup_printf( |
|
| 1773 _("Unable to resolve hostname: %s"), error_message); |
|
| 1774 purple_connection_error_reason(gc, |
|
| 1775 /* should this be a settings error? */ |
|
| 1776 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp); |
|
| 1777 g_free(tmp); |
|
| 1778 return; |
|
| 1779 } |
|
| 1780 |
|
| 1781 ggp_login_to(account, server_addr); |
|
| 1782 } |
|
| 1783 |
|
| 1784 static void |
|
| 1785 ggp_login(PurpleAccount *account) |
|
| 1786 { |
|
| 1787 PurpleConnection *gc; |
|
| 1788 GGPInfo *info; |
|
| 1789 const char *address; |
|
| 1790 |
|
| 1791 gc = purple_account_get_connection(account); |
|
| 1792 info = g_new0(GGPInfo, 1); |
|
| 1793 gc->proto_data = info; |
|
| 1794 |
|
| 1795 address = purple_account_get_string(account, "gg_server", ""); |
|
| 1796 if (address == NULL || address[0] == '\0') { |
|
| 1797 purple_debug_info("gg", "Trying to retrieve address from gg appmsg service\n"); |
|
| 1798 ggp_login_to(account, 0); |
|
| 1799 return; |
|
| 1800 } |
|
| 1801 |
|
| 1802 purple_debug_info("gg", "Using gg server given by user (%s)\n", address); |
|
| 1803 info->dns_query = purple_dnsquery_a_account(account, address, 8074, |
|
| 1804 ggp_login_resolved, account); |
|
| 1805 } |
|
| 1806 |
|
| 1807 static void ggp_close(PurpleConnection *gc) |
|
| 1808 { |
|
| 1809 if (gc == NULL) { |
|
| 1810 purple_debug_info("gg", "gc == NULL\n"); |
|
| 1811 return; |
|
| 1812 } |
|
| 1813 |
|
| 1814 if (gc->proto_data) { |
|
| 1815 PurpleAccount *account = purple_connection_get_account(gc); |
|
| 1816 PurpleStatus *status; |
|
| 1817 GGPInfo *info = gc->proto_data; |
|
| 1818 |
|
| 1819 if (info->dns_query) |
|
| 1820 purple_dnsquery_destroy(info->dns_query); |
|
| 1821 |
|
| 1822 status = purple_account_get_active_status(account); |
|
| 1823 |
|
| 1824 if (info->session != NULL) { |
|
| 1825 ggp_set_status(account, status); |
|
| 1826 gg_logoff(info->session); |
|
| 1827 gg_free_session(info->session); |
|
| 1828 } |
|
| 1829 |
|
| 1830 purple_account_set_bool(account, "status_broadcasting", info->status_broadcasting); |
|
| 1831 |
|
| 1832 /* Immediately close any notifications on this handle since that process depends |
|
| 1833 * upon the contents of info->searches, which we are about to destroy. |
|
| 1834 */ |
|
| 1835 purple_notify_close_with_handle(gc); |
|
| 1836 |
|
| 1837 ggp_search_destroy(info->searches); |
|
| 1838 g_list_free(info->pending_richtext_messages); |
|
| 1839 g_hash_table_destroy(info->pending_images); |
|
| 1840 g_free(info); |
|
| 1841 gc->proto_data = NULL; |
|
| 1842 } |
|
| 1843 |
|
| 1844 if (gc->inpa > 0) |
|
| 1845 purple_input_remove(gc->inpa); |
|
| 1846 |
|
| 1847 purple_debug_info("gg", "Connection closed.\n"); |
|
| 1848 } |
|
| 1849 |
|
| 1850 static int ggp_send_im(PurpleConnection *gc, const char *who, const char *msg, |
|
| 1851 PurpleMessageFlags flags) |
|
| 1852 { |
|
| 1853 GGPInfo *info = gc->proto_data; |
|
| 1854 char *tmp, *plain; |
|
| 1855 int ret = 1; |
|
| 1856 unsigned char format[1024]; |
|
| 1857 unsigned int format_length = sizeof(struct gg_msg_richtext); |
|
| 1858 gint pos = 0; |
|
| 1859 GData *attribs; |
|
| 1860 const char *start, *end = NULL, *last; |
|
| 1861 |
|
| 1862 if (msg == NULL || *msg == '\0') { |
|
| 1863 return 0; |
|
| 1864 } |
|
| 1865 |
|
| 1866 last = msg; |
|
| 1867 |
|
| 1868 /* Check if the message is richtext */ |
|
| 1869 /* TODO: Check formatting, too */ |
|
| 1870 if(purple_markup_find_tag("img", last, &start, &end, &attribs)) { |
|
| 1871 |
|
| 1872 GString *string_buffer = g_string_new(NULL); |
|
| 1873 struct gg_msg_richtext fmt; |
|
| 1874 |
|
| 1875 do { |
|
| 1876 PurpleStoredImage *image; |
|
| 1877 const char *id; |
|
| 1878 |
|
| 1879 /* Add text before the image */ |
|
| 1880 if(start - last) { |
|
| 1881 pos = pos + g_utf8_strlen(last, start - last); |
|
| 1882 g_string_append_len(string_buffer, last, start - last); |
|
| 1883 } |
|
| 1884 |
|
| 1885 if((id = g_datalist_get_data(&attribs, "id")) && (image = purple_imgstore_find_by_id(atoi(id)))) { |
|
| 1886 struct gg_msg_richtext_format actformat; |
|
| 1887 struct gg_msg_richtext_image actimage; |
|
| 1888 gint image_size = purple_imgstore_get_size(image); |
|
| 1889 gconstpointer image_bin = purple_imgstore_get_data(image); |
|
| 1890 const char *image_filename = purple_imgstore_get_filename(image); |
|
| 1891 uint32_t crc32 = gg_crc32(0, image_bin, image_size); |
|
| 1892 |
|
| 1893 g_hash_table_insert(info->pending_images, GINT_TO_POINTER(crc32), GINT_TO_POINTER(atoi(id))); |
|
| 1894 purple_imgstore_ref(image); |
|
| 1895 purple_debug_info("gg", "ggp_send_im_richtext: got crc: %u for imgid: %i\n", crc32, atoi(id)); |
|
| 1896 |
|
| 1897 actformat.font = GG_FONT_IMAGE; |
|
| 1898 actformat.position = pos; |
|
| 1899 |
|
| 1900 actimage.unknown1 = 0x0109; |
|
| 1901 actimage.size = gg_fix32(image_size); |
|
| 1902 actimage.crc32 = gg_fix32(crc32); |
|
| 1903 |
|
| 1904 if (actimage.size > 255000) { |
|
| 1905 purple_debug_warning("gg", "ggp_send_im_richtext: image over 255kb!\n"); |
|
| 1906 } else { |
|
| 1907 purple_debug_info("gg", "ggp_send_im_richtext: adding images to richtext, size: %i, crc32: %u, name: %s\n", actimage.size, actimage.crc32, image_filename); |
|
| 1908 |
|
| 1909 memcpy(format + format_length, &actformat, sizeof(actformat)); |
|
| 1910 format_length += sizeof(actformat); |
|
| 1911 memcpy(format + format_length, &actimage, sizeof(actimage)); |
|
| 1912 format_length += sizeof(actimage); |
|
| 1913 } |
|
| 1914 } else { |
|
| 1915 purple_debug_error("gg", "ggp_send_im_richtext: image not found in the image store!"); |
|
| 1916 } |
|
| 1917 |
|
| 1918 last = end + 1; |
|
| 1919 g_datalist_clear(&attribs); |
|
| 1920 |
|
| 1921 } while(purple_markup_find_tag("img", last, &start, &end, &attribs)); |
|
| 1922 |
|
| 1923 /* Add text after the images */ |
|
| 1924 if(last && *last) { |
|
| 1925 /* this is currently not used, but might be useful later? */ |
|
| 1926 /* pos = pos + g_utf8_strlen(last, -1); */ |
|
| 1927 g_string_append(string_buffer, last); |
|
| 1928 } |
|
| 1929 |
|
| 1930 fmt.flag = 2; |
|
| 1931 fmt.length = format_length - sizeof(fmt); |
|
| 1932 memcpy(format, &fmt, sizeof(fmt)); |
|
| 1933 |
|
| 1934 purple_debug_info("gg", "ggp_send_im: richtext msg = %s\n", string_buffer->str); |
|
| 1935 plain = purple_unescape_html(string_buffer->str); |
|
| 1936 g_string_free(string_buffer, TRUE); |
|
| 1937 } else { |
|
| 1938 purple_debug_info("gg", "ggp_send_im: msg = %s\n", msg); |
|
| 1939 plain = purple_unescape_html(msg); |
|
| 1940 } |
|
| 1941 |
|
| 1942 /* |
|
| 1943 tmp = charset_convert(plain, "UTF-8", "CP1250"); |
|
| 1944 */ |
|
| 1945 tmp = g_strdup_printf("%s", plain); |
|
| 1946 |
|
| 1947 if (tmp && (format_length - sizeof(struct gg_msg_richtext))) { |
|
| 1948 if(gg_send_message_richtext(info->session, GG_CLASS_CHAT, ggp_str_to_uin(who), (unsigned char *)tmp, format, format_length) < 0) { |
|
| 1949 ret = -1; |
|
| 1950 } else { |
|
| 1951 ret = 1; |
|
| 1952 } |
|
| 1953 } else if (NULL == tmp || *tmp == 0) { |
|
| 1954 ret = 0; |
|
| 1955 } else if (strlen(tmp) > GG_MSG_MAXSIZE) { |
|
| 1956 ret = -E2BIG; |
|
| 1957 } else if (gg_send_message(info->session, GG_CLASS_CHAT, |
|
| 1958 ggp_str_to_uin(who), (unsigned char *)tmp) < 0) { |
|
| 1959 ret = -1; |
|
| 1960 } else { |
|
| 1961 ret = 1; |
|
| 1962 } |
|
| 1963 |
|
| 1964 g_free(plain); |
|
| 1965 g_free(tmp); |
|
| 1966 |
|
| 1967 return ret; |
|
| 1968 } |
|
| 1969 |
|
| 1970 static unsigned int ggp_send_typing(PurpleConnection *gc, const char *name, PurpleTypingState state) |
|
| 1971 { |
|
| 1972 int dummy_length; // we don't send real length of typed message |
|
| 1973 |
|
| 1974 if (state == PURPLE_TYPED) // not supported |
|
| 1975 return 1; |
|
| 1976 |
|
| 1977 if (state == PURPLE_TYPING) |
|
| 1978 dummy_length = (int)g_random_int(); |
|
| 1979 else // PURPLE_NOT_TYPING |
|
| 1980 dummy_length = 0; |
|
| 1981 |
|
| 1982 gg_typing_notification( |
|
| 1983 ((GGPInfo*)gc->proto_data)->session, |
|
| 1984 ggp_str_to_uin(name), |
|
| 1985 dummy_length); |
|
| 1986 |
|
| 1987 return 1; // wait 1 second before another notification |
|
| 1988 } |
|
| 1989 |
|
| 1990 static void ggp_get_info(PurpleConnection *gc, const char *name) |
|
| 1991 { |
|
| 1992 GGPInfo *info = gc->proto_data; |
|
| 1993 GGPSearchForm *form; |
|
| 1994 guint32 seq; |
|
| 1995 |
|
| 1996 form = ggp_search_form_new(GGP_SEARCH_TYPE_INFO); |
|
| 1997 |
|
| 1998 form->user_data = info; |
|
| 1999 form->uin = g_strdup(name); |
|
| 2000 |
|
| 2001 seq = ggp_search_start(gc, form); |
|
| 2002 ggp_search_add(info->searches, seq, form); |
|
| 2003 purple_debug_info("gg", "ggp_get_info(): Added seq %u", seq); |
|
| 2004 } |
|
| 2005 |
|
| 2006 static int ggp_to_gg_status(PurpleStatus *status, char **msg) |
|
| 2007 { |
|
| 2008 const char *status_id = purple_status_get_id(status); |
|
| 2009 int new_status, new_status_descr; |
|
| 2010 const char *new_msg; |
|
| 2011 |
|
| 2012 g_return_val_if_fail(msg != NULL, 0); |
|
| 2013 |
|
| 2014 purple_debug_info("gg", "ggp_to_gg_status: Requested status = %s\n", |
|
| 2015 status_id); |
|
| 2016 |
|
| 2017 if (purple_strequal(status_id, "available")) { |
|
| 2018 new_status = GG_STATUS_AVAIL; |
|
| 2019 new_status_descr = GG_STATUS_AVAIL_DESCR; |
|
| 2020 } else if (purple_strequal(status_id, "away")) { |
|
| 2021 new_status = GG_STATUS_BUSY; |
|
| 2022 new_status_descr = GG_STATUS_BUSY_DESCR; |
|
| 2023 } else if (purple_strequal(status_id, "unavailable")) { |
|
| 2024 new_status = GG_STATUS_DND; |
|
| 2025 new_status_descr = GG_STATUS_DND_DESCR; |
|
| 2026 } else if (purple_strequal(status_id, "invisible")) { |
|
| 2027 new_status = GG_STATUS_INVISIBLE; |
|
| 2028 new_status_descr = GG_STATUS_INVISIBLE_DESCR; |
|
| 2029 } else if (purple_strequal(status_id, "offline")) { |
|
| 2030 new_status = GG_STATUS_NOT_AVAIL; |
|
| 2031 new_status_descr = GG_STATUS_NOT_AVAIL_DESCR; |
|
| 2032 } else { |
|
| 2033 new_status = GG_STATUS_AVAIL; |
|
| 2034 new_status_descr = GG_STATUS_AVAIL_DESCR; |
|
| 2035 purple_debug_info("gg", |
|
| 2036 "ggp_set_status: unknown status requested (status_id=%s)\n", |
|
| 2037 status_id); |
|
| 2038 } |
|
| 2039 |
|
| 2040 new_msg = purple_status_get_attr_string(status, "message"); |
|
| 2041 |
|
| 2042 if(new_msg) { |
|
| 2043 /* |
|
| 2044 char *tmp = purple_markup_strip_html(new_msg); |
|
| 2045 *msg = charset_convert(tmp, "UTF-8", "CP1250"); |
|
| 2046 g_free(tmp); |
|
| 2047 */ |
|
| 2048 *msg = purple_markup_strip_html(new_msg); |
|
| 2049 |
|
| 2050 return new_status_descr; |
|
| 2051 } else { |
|
| 2052 *msg = NULL; |
|
| 2053 return new_status; |
|
| 2054 } |
|
| 2055 } |
|
| 2056 |
|
| 2057 static void ggp_set_status(PurpleAccount *account, PurpleStatus *status) |
|
| 2058 { |
|
| 2059 PurpleConnection *gc; |
|
| 2060 GGPInfo *info; |
|
| 2061 int new_status; |
|
| 2062 char *new_msg = NULL; |
|
| 2063 |
|
| 2064 if (!purple_status_is_active(status)) |
|
| 2065 return; |
|
| 2066 |
|
| 2067 gc = purple_account_get_connection(account); |
|
| 2068 info = gc->proto_data; |
|
| 2069 |
|
| 2070 new_status = ggp_to_gg_status(status, &new_msg); |
|
| 2071 |
|
| 2072 if (!info->status_broadcasting) |
|
| 2073 new_status = new_status|GG_STATUS_FRIENDS_MASK; |
|
| 2074 |
|
| 2075 if (new_msg == NULL) { |
|
| 2076 gg_change_status(info->session, new_status); |
|
| 2077 } else { |
|
| 2078 gg_change_status_descr(info->session, new_status, new_msg); |
|
| 2079 g_free(new_msg); |
|
| 2080 } |
|
| 2081 |
|
| 2082 ggp_status_fake_to_self(account); |
|
| 2083 |
|
| 2084 } |
|
| 2085 |
|
| 2086 static void ggp_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) |
|
| 2087 { |
|
| 2088 PurpleAccount *account; |
|
| 2089 GGPInfo *info = gc->proto_data; |
|
| 2090 const gchar *name = purple_buddy_get_name(buddy); |
|
| 2091 |
|
| 2092 gg_add_notify(info->session, ggp_str_to_uin(name)); |
|
| 2093 |
|
| 2094 account = purple_connection_get_account(gc); |
|
| 2095 if (purple_strequal(purple_account_get_username(account), name)) { |
|
| 2096 ggp_status_fake_to_self(account); |
|
| 2097 } |
|
| 2098 } |
|
| 2099 |
|
| 2100 static void ggp_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, |
|
| 2101 PurpleGroup *group) |
|
| 2102 { |
|
| 2103 GGPInfo *info = gc->proto_data; |
|
| 2104 |
|
| 2105 gg_remove_notify(info->session, ggp_str_to_uin(purple_buddy_get_name(buddy))); |
|
| 2106 } |
|
| 2107 |
|
| 2108 static void ggp_join_chat(PurpleConnection *gc, GHashTable *data) |
|
| 2109 { |
|
| 2110 GGPInfo *info = gc->proto_data; |
|
| 2111 GGPChat *chat; |
|
| 2112 char *chat_name; |
|
| 2113 GList *l; |
|
| 2114 PurpleConversation *conv; |
|
| 2115 PurpleAccount *account = purple_connection_get_account(gc); |
|
| 2116 |
|
| 2117 chat_name = g_hash_table_lookup(data, "name"); |
|
| 2118 |
|
| 2119 if (chat_name == NULL) |
|
| 2120 return; |
|
| 2121 |
|
| 2122 purple_debug_info("gg", "joined %s chat\n", chat_name); |
|
| 2123 |
|
| 2124 for (l = info->chats; l != NULL; l = l->next) { |
|
| 2125 chat = l->data; |
|
| 2126 |
|
| 2127 if (chat != NULL && g_utf8_collate(chat->name, chat_name) == 0) { |
|
| 2128 purple_notify_error(gc, _("Chat error"), |
|
| 2129 _("This chat name is already in use"), NULL); |
|
| 2130 return; |
|
| 2131 } |
|
| 2132 } |
|
| 2133 |
|
| 2134 ggp_confer_add_new(gc, chat_name); |
|
| 2135 conv = serv_got_joined_chat(gc, info->chats_count, chat_name); |
|
| 2136 purple_conv_chat_add_user(PURPLE_CONV_CHAT(conv), |
|
| 2137 purple_account_get_username(account), NULL, |
|
| 2138 PURPLE_CBFLAGS_NONE, TRUE); |
|
| 2139 } |
|
| 2140 |
|
| 2141 static char *ggp_get_chat_name(GHashTable *data) { |
|
| 2142 return g_strdup(g_hash_table_lookup(data, "name")); |
|
| 2143 } |
|
| 2144 |
|
| 2145 static int ggp_chat_send(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags) |
|
| 2146 { |
|
| 2147 PurpleConversation *conv; |
|
| 2148 GGPInfo *info = gc->proto_data; |
|
| 2149 GGPChat *chat = NULL; |
|
| 2150 GList *l; |
|
| 2151 /* char *msg, *plain; */ |
|
| 2152 gchar *msg; |
|
| 2153 uin_t *uins; |
|
| 2154 int count = 0; |
|
| 2155 |
|
| 2156 if ((conv = purple_find_chat(gc, id)) == NULL) |
|
| 2157 return -EINVAL; |
|
| 2158 |
|
| 2159 for (l = info->chats; l != NULL; l = l->next) { |
|
| 2160 chat = l->data; |
|
| 2161 |
|
| 2162 if (g_utf8_collate(chat->name, conv->name) == 0) { |
|
| 2163 break; |
|
| 2164 } |
|
| 2165 |
|
| 2166 chat = NULL; |
|
| 2167 } |
|
| 2168 |
|
| 2169 if (chat == NULL) { |
|
| 2170 purple_debug_error("gg", |
|
| 2171 "ggp_chat_send: Hm... that's strange. No such chat?\n"); |
|
| 2172 return -EINVAL; |
|
| 2173 } |
|
| 2174 |
|
| 2175 uins = g_new0(uin_t, g_list_length(chat->participants)); |
|
| 2176 |
|
| 2177 for (l = chat->participants; l != NULL; l = l->next) { |
|
| 2178 uin_t uin = GPOINTER_TO_INT(l->data); |
|
| 2179 |
|
| 2180 uins[count++] = uin; |
|
| 2181 } |
|
| 2182 |
|
| 2183 /* |
|
| 2184 plain = purple_unescape_html(message); |
|
| 2185 msg = charset_convert(plain, "UTF-8", "CP1250"); |
|
| 2186 g_free(plain); |
|
| 2187 */ |
|
| 2188 msg = purple_unescape_html(message); |
|
| 2189 gg_send_message_confer(info->session, GG_CLASS_CHAT, count, uins, |
|
| 2190 (unsigned char *)msg); |
|
| 2191 g_free(msg); |
|
| 2192 g_free(uins); |
|
| 2193 |
|
| 2194 serv_got_chat_in(gc, id, |
|
| 2195 purple_account_get_username(purple_connection_get_account(gc)), |
|
| 2196 flags, message, time(NULL)); |
|
| 2197 |
|
| 2198 return 0; |
|
| 2199 } |
|
| 2200 |
|
| 2201 static void ggp_keepalive(PurpleConnection *gc) |
|
| 2202 { |
|
| 2203 GGPInfo *info = gc->proto_data; |
|
| 2204 |
|
| 2205 /* purple_debug_info("gg", "Keeping connection alive....\n"); */ |
|
| 2206 |
|
| 2207 if (gg_ping(info->session) < 0) { |
|
| 2208 purple_debug_info("gg", "Not connected to the server " |
|
| 2209 "or gg_session is not correct\n"); |
|
| 2210 purple_connection_error_reason (gc, |
|
| 2211 PURPLE_CONNECTION_ERROR_NETWORK_ERROR, |
|
| 2212 _("Not connected to the server")); |
|
| 2213 } |
|
| 2214 } |
|
| 2215 |
|
| 2216 static GList *ggp_actions(PurplePlugin *plugin, gpointer context) |
|
| 2217 { |
|
| 2218 GList *m = NULL; |
|
| 2219 PurplePluginAction *act; |
|
| 2220 |
|
| 2221 act = purple_plugin_action_new(_("Find buddies..."), |
|
| 2222 ggp_find_buddies); |
|
| 2223 m = g_list_append(m, act); |
|
| 2224 |
|
| 2225 act = purple_plugin_action_new(_("Change status broadcasting"), |
|
| 2226 ggp_action_change_status_broadcasting); |
|
| 2227 m = g_list_append(m, act); |
|
| 2228 |
|
| 2229 m = g_list_append(m, NULL); |
|
| 2230 |
|
| 2231 act = purple_plugin_action_new(_("Save buddylist to file..."), |
|
| 2232 ggp_action_buddylist_save); |
|
| 2233 m = g_list_append(m, act); |
|
| 2234 |
|
| 2235 act = purple_plugin_action_new(_("Load buddylist from file..."), |
|
| 2236 ggp_action_buddylist_load); |
|
| 2237 m = g_list_append(m, act); |
|
| 2238 |
|
| 2239 return m; |
|
| 2240 } |
|
| 2241 |
|
| 2242 static gboolean ggp_offline_message(const PurpleBuddy *buddy) |
|
| 2243 { |
|
| 2244 return TRUE; |
|
| 2245 } |
|
| 2246 |
|
| 2247 static gboolean ggp_load(PurplePlugin *plugin) |
|
| 2248 { |
|
| 2249 purple_debug_info("gg", "Loading Gadu-Gadu protocol plugin with " |
|
| 2250 "libgadu %s...\n", gg_libgadu_version()); |
|
| 2251 |
|
| 2252 gg_is_gpl_compliant(); |
|
| 2253 |
|
| 2254 return TRUE; |
|
| 2255 } |
|
| 2256 |
|
| 2257 static PurplePluginProtocolInfo prpl_info = |
|
| 2258 { |
|
| 2259 OPT_PROTO_IM_IMAGE, |
|
| 2260 NULL, /* user_splits */ |
|
| 2261 NULL, /* protocol_options */ |
|
| 2262 {"png", 32, 32, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */ |
|
| 2263 ggp_list_icon, /* list_icon */ |
|
| 2264 NULL, /* list_emblem */ |
|
| 2265 ggp_status_text, /* status_text */ |
|
| 2266 ggp_tooltip_text, /* tooltip_text */ |
|
| 2267 ggp_status_types, /* status_types */ |
|
| 2268 ggp_blist_node_menu, /* blist_node_menu */ |
|
| 2269 ggp_chat_info, /* chat_info */ |
|
| 2270 NULL, /* chat_info_defaults */ |
|
| 2271 ggp_login, /* login */ |
|
| 2272 ggp_close, /* close */ |
|
| 2273 ggp_send_im, /* send_im */ |
|
| 2274 NULL, /* set_info */ |
|
| 2275 ggp_send_typing, /* send_typing */ |
|
| 2276 ggp_get_info, /* get_info */ |
|
| 2277 ggp_set_status, /* set_away */ |
|
| 2278 NULL, /* set_idle */ |
|
| 2279 NULL, /* change_passwd */ |
|
| 2280 ggp_add_buddy, /* add_buddy */ |
|
| 2281 NULL, /* add_buddies */ |
|
| 2282 ggp_remove_buddy, /* remove_buddy */ |
|
| 2283 NULL, /* remove_buddies */ |
|
| 2284 NULL, /* add_permit */ |
|
| 2285 ggp_add_deny, /* add_deny */ |
|
| 2286 NULL, /* rem_permit */ |
|
| 2287 ggp_rem_deny, /* rem_deny */ |
|
| 2288 NULL, /* set_permit_deny */ |
|
| 2289 ggp_join_chat, /* join_chat */ |
|
| 2290 NULL, /* reject_chat */ |
|
| 2291 ggp_get_chat_name, /* get_chat_name */ |
|
| 2292 NULL, /* chat_invite */ |
|
| 2293 NULL, /* chat_leave */ |
|
| 2294 NULL, /* chat_whisper */ |
|
| 2295 ggp_chat_send, /* chat_send */ |
|
| 2296 ggp_keepalive, /* keepalive */ |
|
| 2297 NULL, /* register_user */ |
|
| 2298 NULL, /* get_cb_info */ |
|
| 2299 NULL, /* get_cb_away */ |
|
| 2300 NULL, /* alias_buddy */ |
|
| 2301 NULL, /* group_buddy */ |
|
| 2302 NULL, /* rename_group */ |
|
| 2303 NULL, /* buddy_free */ |
|
| 2304 NULL, /* convo_closed */ |
|
| 2305 NULL, /* normalize */ |
|
| 2306 NULL, /* set_buddy_icon */ |
|
| 2307 NULL, /* remove_group */ |
|
| 2308 NULL, /* get_cb_real_name */ |
|
| 2309 NULL, /* set_chat_topic */ |
|
| 2310 NULL, /* find_blist_chat */ |
|
| 2311 NULL, /* roomlist_get_list */ |
|
| 2312 NULL, /* roomlist_cancel */ |
|
| 2313 NULL, /* roomlist_expand_category */ |
|
| 2314 NULL, /* can_receive_file */ |
|
| 2315 NULL, /* send_file */ |
|
| 2316 NULL, /* new_xfer */ |
|
| 2317 ggp_offline_message, /* offline_message */ |
|
| 2318 NULL, /* whiteboard_prpl_ops */ |
|
| 2319 NULL, /* send_raw */ |
|
| 2320 NULL, /* roomlist_room_serialize */ |
|
| 2321 NULL, /* unregister_user */ |
|
| 2322 NULL, /* send_attention */ |
|
| 2323 NULL, /* get_attention_types */ |
|
| 2324 sizeof(PurplePluginProtocolInfo), /* struct_size */ |
|
| 2325 NULL, /* get_account_text_table */ |
|
| 2326 NULL, /* initiate_media */ |
|
| 2327 NULL, /* can_do_media */ |
|
| 2328 NULL, /* get_moods */ |
|
| 2329 NULL, /* set_public_alias */ |
|
| 2330 NULL, /* get_public_alias */ |
|
| 2331 NULL, /* add_buddy_with_invite */ |
|
| 2332 NULL, /* add_buddies_with_invite */ |
|
| 2333 NULL, /* get_cb_alias */ |
|
| 2334 NULL, /* chat_can_receive_file */ |
|
| 2335 NULL, /* chat_send_file */ |
|
| 2336 }; |
|
| 2337 |
|
| 2338 static PurplePluginInfo info = { |
|
| 2339 PURPLE_PLUGIN_MAGIC, /* magic */ |
|
| 2340 PURPLE_MAJOR_VERSION, /* major_version */ |
|
| 2341 PURPLE_MINOR_VERSION, /* minor_version */ |
|
| 2342 PURPLE_PLUGIN_PROTOCOL, /* plugin type */ |
|
| 2343 NULL, /* ui_requirement */ |
|
| 2344 0, /* flags */ |
|
| 2345 NULL, /* dependencies */ |
|
| 2346 PURPLE_PRIORITY_DEFAULT, /* priority */ |
|
| 2347 |
|
| 2348 "prpl-gg", /* id */ |
|
| 2349 "Gadu-Gadu", /* name */ |
|
| 2350 DISPLAY_VERSION, /* version */ |
|
| 2351 |
|
| 2352 N_("Gadu-Gadu Protocol Plugin"), /* summary */ |
|
| 2353 N_("Polish popular IM"), /* description */ |
|
| 2354 "boler@sourceforge.net", /* author */ |
|
| 2355 PURPLE_WEBSITE, /* homepage */ |
|
| 2356 |
|
| 2357 ggp_load, /* load */ |
|
| 2358 NULL, /* unload */ |
|
| 2359 NULL, /* destroy */ |
|
| 2360 |
|
| 2361 NULL, /* ui_info */ |
|
| 2362 &prpl_info, /* extra_info */ |
|
| 2363 NULL, /* prefs_info */ |
|
| 2364 ggp_actions, /* actions */ |
|
| 2365 |
|
| 2366 /* padding */ |
|
| 2367 NULL, |
|
| 2368 NULL, |
|
| 2369 NULL, |
|
| 2370 NULL |
|
| 2371 }; |
|
| 2372 |
|
| 2373 static void |
|
| 2374 purple_gg_debug_handler(int level, const char * format, va_list args) |
|
| 2375 { |
|
| 2376 PurpleDebugLevel purple_level; |
|
| 2377 char msgbuff[1000]; |
|
| 2378 int ret; |
|
| 2379 |
|
| 2380 /* Don't use glib's printf family, since it might not support |
|
| 2381 * system-specific formatting modifiers (like %Iu for size on win32). */ |
|
| 2382 ret = vsnprintf(msgbuff, sizeof(msgbuff) / sizeof(char), format, args); |
|
| 2383 |
|
| 2384 if (ret <= 0) { |
|
| 2385 purple_debug_fatal("gg", |
|
| 2386 "failed to printf the following message: %s", |
|
| 2387 format ? format : "(null)\n"); |
|
| 2388 |
|
| 2389 return; |
|
| 2390 } |
|
| 2391 |
|
| 2392 /* This is pretty pointless since the GG_DEBUG levels don't correspond to |
|
| 2393 * the purple ones */ |
|
| 2394 switch (level) { |
|
| 2395 case GG_DEBUG_FUNCTION: |
|
| 2396 purple_level = PURPLE_DEBUG_INFO; |
|
| 2397 break; |
|
| 2398 case GG_DEBUG_MISC: |
|
| 2399 case GG_DEBUG_NET: |
|
| 2400 case GG_DEBUG_DUMP: |
|
| 2401 case GG_DEBUG_TRAFFIC: |
|
| 2402 default: |
|
| 2403 purple_level = PURPLE_DEBUG_MISC; |
|
| 2404 break; |
|
| 2405 } |
|
| 2406 |
|
| 2407 purple_debug(purple_level, "gg", "%s", msgbuff); |
|
| 2408 } |
|
| 2409 |
|
| 2410 static void init_plugin(PurplePlugin *plugin) |
|
| 2411 { |
|
| 2412 PurpleAccountOption *option; |
|
| 2413 GList *encryption_options = NULL; |
|
| 2414 |
|
| 2415 option = purple_account_option_string_new(_("Nickname"), |
|
| 2416 "nick", _("Gadu-Gadu User")); |
|
| 2417 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, |
|
| 2418 option); |
|
| 2419 |
|
| 2420 option = purple_account_option_string_new(_("GG server"), |
|
| 2421 "gg_server", ""); |
|
| 2422 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, |
|
| 2423 option); |
|
| 2424 |
|
| 2425 #define ADD_VALUE(list, desc, v) { \ |
|
| 2426 PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \ |
|
| 2427 kvp->key = g_strdup((desc)); \ |
|
| 2428 kvp->value = g_strdup((v)); \ |
|
| 2429 list = g_list_append(list, kvp); \ |
|
| 2430 } |
|
| 2431 |
|
| 2432 ADD_VALUE(encryption_options, _("Don't use encryption"), "none"); |
|
| 2433 ADD_VALUE(encryption_options, _("Use encryption if available"), |
|
| 2434 "opportunistic_tls"); |
|
| 2435 #if 0 |
|
| 2436 /* TODO */ |
|
| 2437 ADD_VALUE(encryption_options, _("Require encryption"), "require_tls"); |
|
| 2438 #endif |
|
| 2439 |
|
| 2440 option = purple_account_option_list_new(_("Connection security"), |
|
| 2441 "encryption", encryption_options); |
|
| 2442 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, |
|
| 2443 option); |
|
| 2444 |
|
| 2445 my_protocol = plugin; |
|
| 2446 |
|
| 2447 gg_debug_handler = purple_gg_debug_handler; |
|
| 2448 } |
|
| 2449 |
|
| 2450 PURPLE_INIT_PLUGIN(gg, init_plugin, info); |
|
| 2451 |
|
| 2452 /* vim: set ts=8 sts=0 sw=8 noet: */ |
|