| 1 /* |
|
| 2 |
|
| 3 silcpurple_chat.c |
|
| 4 |
|
| 5 Author: Pekka Riikonen <priikone@silcnet.org> |
|
| 6 |
|
| 7 Copyright (C) 2004 - 2007 Pekka Riikonen |
|
| 8 |
|
| 9 This program is free software; you can redistribute it and/or modify |
|
| 10 it under the terms of the GNU General Public License as published by |
|
| 11 the Free Software Foundation; version 2 of the License. |
|
| 12 |
|
| 13 This program is distributed in the hope that it will be useful, |
|
| 14 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 GNU General Public License for more details. |
|
| 17 |
|
| 18 */ |
|
| 19 |
|
| 20 #include <glib/gi18n-lib.h> |
|
| 21 |
|
| 22 #include "silcpurple.h" |
|
| 23 #include "wb.h" |
|
| 24 |
|
| 25 /***************************** Channel Routines ******************************/ |
|
| 26 |
|
| 27 GList *silcpurple_chat_info(PurpleProtocolChat *protocol_chat, PurpleConnection *gc) |
|
| 28 { |
|
| 29 GList *ci = NULL; |
|
| 30 PurpleProtocolChatEntry *pce; |
|
| 31 |
|
| 32 pce = g_new0(PurpleProtocolChatEntry, 1); |
|
| 33 pce->label = _("_Channel:"); |
|
| 34 pce->identifier = "channel"; |
|
| 35 pce->required = TRUE; |
|
| 36 ci = g_list_append(ci, pce); |
|
| 37 |
|
| 38 pce = g_new0(PurpleProtocolChatEntry, 1); |
|
| 39 pce->label = _("_Passphrase:"); |
|
| 40 pce->identifier = "passphrase"; |
|
| 41 pce->secret = TRUE; |
|
| 42 ci = g_list_append(ci, pce); |
|
| 43 |
|
| 44 return ci; |
|
| 45 } |
|
| 46 |
|
| 47 GHashTable *silcpurple_chat_info_defaults(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, const char *chat_name) |
|
| 48 { |
|
| 49 GHashTable *defaults; |
|
| 50 |
|
| 51 defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); |
|
| 52 |
|
| 53 if (chat_name != NULL) |
|
| 54 g_hash_table_insert(defaults, "channel", g_strdup(chat_name)); |
|
| 55 |
|
| 56 return defaults; |
|
| 57 } |
|
| 58 |
|
| 59 static void |
|
| 60 silcpurple_chat_getinfo(PurpleConnection *gc, GHashTable *components); |
|
| 61 |
|
| 62 static void |
|
| 63 silcpurple_chat_getinfo_res(SilcClient client, |
|
| 64 SilcClientConnection conn, |
|
| 65 SilcStatus status, |
|
| 66 SilcDList channels, |
|
| 67 void *context) |
|
| 68 { |
|
| 69 GHashTable *components = context; |
|
| 70 PurpleConnection *gc = client->application; |
|
| 71 const char *chname; |
|
| 72 char tmp[256]; |
|
| 73 |
|
| 74 chname = g_hash_table_lookup(components, "channel"); |
|
| 75 if (!chname) |
|
| 76 return; |
|
| 77 |
|
| 78 if (!channels) { |
|
| 79 g_snprintf(tmp, sizeof(tmp), |
|
| 80 _("Channel %s does not exist in the network"), chname); |
|
| 81 purple_notify_error(gc, _("Channel Information"), |
|
| 82 _("Cannot get channel information"), tmp, |
|
| 83 purple_request_cpar_from_connection(gc)); |
|
| 84 return; |
|
| 85 } |
|
| 86 |
|
| 87 silcpurple_chat_getinfo(gc, components); |
|
| 88 } |
|
| 89 |
|
| 90 |
|
| 91 static void |
|
| 92 silcpurple_chat_getinfo(PurpleConnection *gc, GHashTable *components) |
|
| 93 { |
|
| 94 SilcPurple sg = purple_connection_get_protocol_data(gc); |
|
| 95 const char *chname; |
|
| 96 char tmp[256], *tmp2; |
|
| 97 GString *s; |
|
| 98 SilcChannelEntry channel; |
|
| 99 SilcHashTableList htl; |
|
| 100 SilcChannelUser chu; |
|
| 101 |
|
| 102 if (!components) |
|
| 103 return; |
|
| 104 |
|
| 105 chname = g_hash_table_lookup(components, "channel"); |
|
| 106 if (!chname) |
|
| 107 return; |
|
| 108 channel = silc_client_get_channel(sg->client, sg->conn, |
|
| 109 (char *)chname); |
|
| 110 if (!channel) { |
|
| 111 silc_client_get_channel_resolve(sg->client, sg->conn, |
|
| 112 (char *)chname, |
|
| 113 silcpurple_chat_getinfo_res, |
|
| 114 components); |
|
| 115 return; |
|
| 116 } |
|
| 117 |
|
| 118 s = g_string_new(""); |
|
| 119 tmp2 = g_markup_escape_text(channel->channel_name, -1); |
|
| 120 g_string_append_printf(s, _("<b>Channel Name:</b> %s"), tmp2); |
|
| 121 g_free(tmp2); |
|
| 122 if (channel->user_list && silc_hash_table_count(channel->user_list)) |
|
| 123 g_string_append_printf(s, _("<br><b>User Count:</b> %d"), |
|
| 124 (int)silc_hash_table_count(channel->user_list)); |
|
| 125 |
|
| 126 silc_hash_table_list(channel->user_list, &htl); |
|
| 127 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { |
|
| 128 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) { |
|
| 129 tmp2 = g_markup_escape_text(chu->client->nickname, -1); |
|
| 130 g_string_append_printf(s, _("<br><b>Channel Founder:</b> %s"), |
|
| 131 tmp2); |
|
| 132 g_free(tmp2); |
|
| 133 break; |
|
| 134 } |
|
| 135 } |
|
| 136 silc_hash_table_list_reset(&htl); |
|
| 137 |
|
| 138 if (channel->cipher) |
|
| 139 g_string_append_printf(s, _("<br><b>Channel Cipher:</b> %s"), |
|
| 140 channel->cipher); |
|
| 141 |
|
| 142 if (channel->hmac) |
|
| 143 /* Definition of HMAC: http://en.wikipedia.org/wiki/HMAC */ |
|
| 144 g_string_append_printf(s, _("<br><b>Channel HMAC:</b> %s"), |
|
| 145 channel->hmac); |
|
| 146 |
|
| 147 if (channel->topic) { |
|
| 148 tmp2 = g_markup_escape_text(channel->topic, -1); |
|
| 149 g_string_append_printf(s, _("<br><b>Channel Topic:</b><br>%s"), tmp2); |
|
| 150 g_free(tmp2); |
|
| 151 } |
|
| 152 |
|
| 153 if (channel->mode) { |
|
| 154 g_string_append(s, _("<br><b>Channel Modes:</b> ")); |
|
| 155 silcpurple_get_chmode_string(channel->mode, tmp, sizeof(tmp)); |
|
| 156 g_string_append(s, tmp); |
|
| 157 } |
|
| 158 |
|
| 159 if (channel->founder_key) { |
|
| 160 char *fingerprint, *babbleprint; |
|
| 161 unsigned char *pk; |
|
| 162 SilcUInt32 pk_len; |
|
| 163 pk = silc_pkcs_public_key_encode(channel->founder_key, &pk_len); |
|
| 164 if (pk) { |
|
| 165 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); |
|
| 166 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); |
|
| 167 |
|
| 168 g_string_append_printf(s, _("<br><b>Founder Key Fingerprint:</b><br>%s"), fingerprint); |
|
| 169 g_string_append_printf(s, _("<br><b>Founder Key Babbleprint:</b><br>%s"), babbleprint); |
|
| 170 |
|
| 171 silc_free(fingerprint); |
|
| 172 silc_free(babbleprint); |
|
| 173 silc_free(pk); |
|
| 174 } |
|
| 175 } |
|
| 176 |
|
| 177 purple_notify_formatted(gc, NULL, _("Channel Information"), NULL, s->str, NULL, NULL); |
|
| 178 g_string_free(s, TRUE); |
|
| 179 } |
|
| 180 |
|
| 181 |
|
| 182 static void |
|
| 183 silcpurple_chat_getinfo_menu(PurpleBlistNode *node, gpointer data) |
|
| 184 { |
|
| 185 PurpleChat *chat = (PurpleChat *)node; |
|
| 186 PurpleAccount *account = purple_chat_get_account(chat); |
|
| 187 silcpurple_chat_getinfo(purple_account_get_connection(account), |
|
| 188 purple_chat_get_components(chat)); |
|
| 189 } |
|
| 190 |
|
| 191 |
|
| 192 /************************* Channel Authentication ****************************/ |
|
| 193 |
|
| 194 typedef struct { |
|
| 195 SilcPurple sg; |
|
| 196 SilcChannelEntry channel; |
|
| 197 PurpleChat *c; |
|
| 198 SilcDList pubkeys; |
|
| 199 } *SilcPurpleChauth; |
|
| 200 |
|
| 201 static void |
|
| 202 silcpurple_chat_chpk_add(void *user_data, const char *name) |
|
| 203 { |
|
| 204 SilcPurpleChauth sgc = (SilcPurpleChauth)user_data; |
|
| 205 SilcPurple sg = sgc->sg; |
|
| 206 SilcClient client = sg->client; |
|
| 207 SilcClientConnection conn = sg->conn; |
|
| 208 SilcPublicKey public_key; |
|
| 209 SilcBuffer chpks, pk, chidp; |
|
| 210 unsigned char mode[4]; |
|
| 211 SilcUInt32 m; |
|
| 212 |
|
| 213 /* Load the public key */ |
|
| 214 if (!silc_pkcs_load_public_key(name, &public_key)) { |
|
| 215 silcpurple_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys); |
|
| 216 silc_dlist_uninit(sgc->pubkeys); |
|
| 217 silc_free(sgc); |
|
| 218 purple_notify_error(client->application, |
|
| 219 _("Add Channel Public Key"), |
|
| 220 _("Could not load public key"), NULL, NULL); |
|
| 221 return; |
|
| 222 } |
|
| 223 |
|
| 224 pk = silc_public_key_payload_encode(public_key); |
|
| 225 chpks = silc_buffer_alloc_size(2); |
|
| 226 SILC_PUT16_MSB(1, chpks->head); |
|
| 227 chpks = silc_argument_payload_encode_one(chpks, pk->data, |
|
| 228 silc_buffer_len(pk), 0x00); |
|
| 229 silc_buffer_free(pk); |
|
| 230 |
|
| 231 m = sgc->channel->mode; |
|
| 232 m |= SILC_CHANNEL_MODE_CHANNEL_AUTH; |
|
| 233 |
|
| 234 /* Send CMODE */ |
|
| 235 SILC_PUT32_MSB(m, mode); |
|
| 236 chidp = silc_id_payload_encode(&sgc->channel->id, SILC_ID_CHANNEL); |
|
| 237 silc_client_command_send(client, conn, SILC_COMMAND_CMODE, |
|
| 238 silcpurple_command_reply, NULL, 3, |
|
| 239 1, chidp->data, silc_buffer_len(chidp), |
|
| 240 2, mode, sizeof(mode), |
|
| 241 9, chpks->data, silc_buffer_len(chpks)); |
|
| 242 silc_buffer_free(chpks); |
|
| 243 silc_buffer_free(chidp); |
|
| 244 if (sgc->pubkeys) { |
|
| 245 silc_dlist_start(sgc->pubkeys); |
|
| 246 while ((public_key = silc_dlist_get(sgc->pubkeys))) |
|
| 247 silc_pkcs_public_key_free(public_key); |
|
| 248 silc_dlist_uninit(sgc->pubkeys); |
|
| 249 } |
|
| 250 silc_free(sgc); |
|
| 251 } |
|
| 252 |
|
| 253 static void |
|
| 254 silcpurple_chat_chpk_cancel(void *user_data, const char *name) |
|
| 255 { |
|
| 256 SilcPurpleChauth sgc = (SilcPurpleChauth)user_data; |
|
| 257 SilcPublicKey public_key; |
|
| 258 |
|
| 259 silcpurple_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys); |
|
| 260 |
|
| 261 if (sgc->pubkeys) { |
|
| 262 silc_dlist_start(sgc->pubkeys); |
|
| 263 while ((public_key = silc_dlist_get(sgc->pubkeys))) |
|
| 264 silc_pkcs_public_key_free(public_key); |
|
| 265 silc_dlist_uninit(sgc->pubkeys); |
|
| 266 } |
|
| 267 silc_free(sgc); |
|
| 268 } |
|
| 269 |
|
| 270 static void |
|
| 271 silcpurple_chat_chpk_cb(SilcPurpleChauth sgc, PurpleRequestFields *fields) |
|
| 272 { |
|
| 273 SilcPurple sg = sgc->sg; |
|
| 274 SilcClient client = sg->client; |
|
| 275 SilcClientConnection conn = sg->conn; |
|
| 276 PurpleRequestField *f; |
|
| 277 GList *list; |
|
| 278 SilcPublicKey public_key; |
|
| 279 SilcBuffer chpks, pk, chidp; |
|
| 280 SilcUInt16 c = 0, ct; |
|
| 281 unsigned char mode[4]; |
|
| 282 SilcUInt32 m; |
|
| 283 |
|
| 284 f = purple_request_fields_get_field(fields, "list"); |
|
| 285 if (!purple_request_field_list_get_selected(f)) { |
|
| 286 /* Add new public key */ |
|
| 287 purple_request_file(sg->gc, _("Open Public Key..."), NULL, FALSE, |
|
| 288 G_CALLBACK(silcpurple_chat_chpk_add), |
|
| 289 G_CALLBACK(silcpurple_chat_chpk_cancel), |
|
| 290 purple_request_cpar_from_connection(sg->gc), sgc); |
|
| 291 return; |
|
| 292 } |
|
| 293 |
|
| 294 list = purple_request_field_list_get_items(f); |
|
| 295 chpks = silc_buffer_alloc_size(2); |
|
| 296 |
|
| 297 for (ct = 0; list; list = list->next, ct++) { |
|
| 298 PurpleKeyValuePair *item = list->data; |
|
| 299 |
|
| 300 public_key = purple_request_field_list_get_data(f, item->key); |
|
| 301 if (purple_request_field_list_is_selected(f, item->key)) { |
|
| 302 /* Delete this public key */ |
|
| 303 pk = silc_public_key_payload_encode(public_key); |
|
| 304 chpks = silc_argument_payload_encode_one(chpks, pk->data, |
|
| 305 silc_buffer_len(pk), 0x01); |
|
| 306 silc_buffer_free(pk); |
|
| 307 c++; |
|
| 308 } |
|
| 309 } |
|
| 310 if (!c) { |
|
| 311 silc_buffer_free(chpks); |
|
| 312 return; |
|
| 313 } |
|
| 314 SILC_PUT16_MSB(c, chpks->head); |
|
| 315 |
|
| 316 m = sgc->channel->mode; |
|
| 317 if (ct == c) |
|
| 318 m &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH; |
|
| 319 |
|
| 320 /* Send CMODE */ |
|
| 321 SILC_PUT32_MSB(m, mode); |
|
| 322 chidp = silc_id_payload_encode(&sgc->channel->id, SILC_ID_CHANNEL); |
|
| 323 silc_client_command_send(client, conn, SILC_COMMAND_CMODE, |
|
| 324 silcpurple_command_reply, NULL, 3, |
|
| 325 1, chidp->data, silc_buffer_len(chidp), |
|
| 326 2, mode, sizeof(mode), |
|
| 327 9, chpks->data, silc_buffer_len(chpks)); |
|
| 328 silc_buffer_free(chpks); |
|
| 329 silc_buffer_free(chidp); |
|
| 330 if (sgc->pubkeys) { |
|
| 331 silc_dlist_start(sgc->pubkeys); |
|
| 332 while ((public_key = silc_dlist_get(sgc->pubkeys))) |
|
| 333 silc_pkcs_public_key_free(public_key); |
|
| 334 silc_dlist_uninit(sgc->pubkeys); |
|
| 335 } |
|
| 336 silc_free(sgc); |
|
| 337 } |
|
| 338 |
|
| 339 static void |
|
| 340 silcpurple_chat_chauth_ok(SilcPurpleChauth sgc, PurpleRequestFields *fields) |
|
| 341 { |
|
| 342 SilcPurple sg = sgc->sg; |
|
| 343 PurpleRequestField *f; |
|
| 344 SilcPublicKey public_key; |
|
| 345 const char *curpass, *val; |
|
| 346 int set; |
|
| 347 |
|
| 348 f = purple_request_fields_get_field(fields, "passphrase"); |
|
| 349 val = purple_request_field_string_get_value(f); |
|
| 350 curpass = purple_blist_node_get_string((PurpleBlistNode *)sgc->c, "passphrase"); |
|
| 351 |
|
| 352 if (!val && curpass) |
|
| 353 set = 0; |
|
| 354 else if (val && !curpass) |
|
| 355 set = 1; |
|
| 356 else if (val && curpass && !purple_strequal(val, curpass)) |
|
| 357 set = 1; |
|
| 358 else |
|
| 359 set = -1; |
|
| 360 |
|
| 361 if (set == 1) { |
|
| 362 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", |
|
| 363 sgc->channel->channel_name, "+a", val, NULL); |
|
| 364 purple_blist_node_set_string((PurpleBlistNode *)sgc->c, "passphrase", val); |
|
| 365 } else if (set == 0) { |
|
| 366 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", |
|
| 367 sgc->channel->channel_name, "-a", NULL); |
|
| 368 purple_blist_node_remove_setting((PurpleBlistNode *)sgc->c, "passphrase"); |
|
| 369 } |
|
| 370 |
|
| 371 if (sgc->pubkeys) { |
|
| 372 silc_dlist_start(sgc->pubkeys); |
|
| 373 while ((public_key = silc_dlist_get(sgc->pubkeys))) |
|
| 374 silc_pkcs_public_key_free(public_key); |
|
| 375 silc_dlist_uninit(sgc->pubkeys); |
|
| 376 } |
|
| 377 silc_free(sgc); |
|
| 378 } |
|
| 379 |
|
| 380 void silcpurple_chat_chauth_show(SilcPurple sg, SilcChannelEntry channel, |
|
| 381 SilcDList channel_pubkeys) |
|
| 382 { |
|
| 383 SilcPublicKey public_key; |
|
| 384 SilcSILCPublicKey silc_pubkey; |
|
| 385 unsigned char *pk; |
|
| 386 SilcUInt32 pk_len; |
|
| 387 char *fingerprint, *babbleprint; |
|
| 388 SilcPublicKeyIdentifier ident; |
|
| 389 char tmp2[1024]; |
|
| 390 const gchar *t; |
|
| 391 PurpleRequestFields *fields; |
|
| 392 PurpleRequestFieldGroup *g; |
|
| 393 PurpleRequestField *f; |
|
| 394 SilcPurpleChauth sgc; |
|
| 395 const char *curpass = NULL; |
|
| 396 |
|
| 397 sgc = silc_calloc(1, sizeof(*sgc)); |
|
| 398 if (!sgc) |
|
| 399 return; |
|
| 400 sgc->sg = sg; |
|
| 401 sgc->channel = channel; |
|
| 402 |
|
| 403 fields = purple_request_fields_new(); |
|
| 404 |
|
| 405 if (sgc->c) |
|
| 406 curpass = purple_blist_node_get_string((PurpleBlistNode *)sgc->c, "passphrase"); |
|
| 407 |
|
| 408 g = purple_request_field_group_new(NULL); |
|
| 409 f = purple_request_field_string_new("passphrase", _("Channel Passphrase"), |
|
| 410 curpass, FALSE); |
|
| 411 purple_request_field_string_set_masked(f, TRUE); |
|
| 412 purple_request_field_group_add_field(g, f); |
|
| 413 purple_request_fields_add_group(fields, g); |
|
| 414 |
|
| 415 g = purple_request_field_group_new(NULL); |
|
| 416 f = purple_request_field_label_new("l1", _("Channel Public Keys List")); |
|
| 417 purple_request_field_group_add_field(g, f); |
|
| 418 purple_request_fields_add_group(fields, g); |
|
| 419 |
|
| 420 t = _("Channel authentication is used to secure the channel from " |
|
| 421 "unauthorized access. The authentication may be based on " |
|
| 422 "passphrase and digital signatures. If passphrase is set, it " |
|
| 423 "is required to be able to join. If channel public keys are set " |
|
| 424 "then only users whose public keys are listed are able to join."); |
|
| 425 |
|
| 426 if (!channel_pubkeys || !silc_dlist_count(channel_pubkeys)) { |
|
| 427 f = purple_request_field_list_new("list", NULL); |
|
| 428 purple_request_field_group_add_field(g, f); |
|
| 429 purple_request_fields(sg->gc, _("Channel Authentication"), |
|
| 430 _("Channel Authentication"), t, fields, |
|
| 431 _("Add / Remove"), G_CALLBACK(silcpurple_chat_chpk_cb), |
|
| 432 _("OK"), G_CALLBACK(silcpurple_chat_chauth_ok), |
|
| 433 purple_request_cpar_from_connection(sg->gc), sgc); |
|
| 434 if (channel_pubkeys) |
|
| 435 silc_dlist_uninit(channel_pubkeys); |
|
| 436 return; |
|
| 437 } |
|
| 438 sgc->pubkeys = channel_pubkeys; |
|
| 439 |
|
| 440 g = purple_request_field_group_new(NULL); |
|
| 441 f = purple_request_field_list_new("list", NULL); |
|
| 442 purple_request_field_group_add_field(g, f); |
|
| 443 purple_request_fields_add_group(fields, g); |
|
| 444 |
|
| 445 silc_dlist_start(channel_pubkeys); |
|
| 446 while ((public_key = silc_dlist_get(channel_pubkeys))) { |
|
| 447 pk = silc_pkcs_public_key_encode(public_key, &pk_len); |
|
| 448 if (!pk) |
|
| 449 continue; |
|
| 450 fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4); |
|
| 451 babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4); |
|
| 452 |
|
| 453 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key); |
|
| 454 ident = &silc_pubkey->identifier; |
|
| 455 |
|
| 456 g_snprintf(tmp2, sizeof(tmp2), "%s\n %s\n %s", |
|
| 457 ident->realname ? ident->realname : ident->username ? |
|
| 458 ident->username : "", fingerprint, babbleprint); |
|
| 459 purple_request_field_list_add_icon(f, tmp2, NULL, public_key); |
|
| 460 |
|
| 461 silc_free(fingerprint); |
|
| 462 silc_free(babbleprint); |
|
| 463 } |
|
| 464 |
|
| 465 purple_request_field_list_set_multi_select(f, FALSE); |
|
| 466 purple_request_fields(sg->gc, _("Channel Authentication"), |
|
| 467 _("Channel Authentication"), t, fields, |
|
| 468 _("Add / Remove"), G_CALLBACK(silcpurple_chat_chpk_cb), |
|
| 469 _("OK"), G_CALLBACK(silcpurple_chat_chauth_ok), |
|
| 470 purple_request_cpar_from_connection(sg->gc), sgc); |
|
| 471 } |
|
| 472 |
|
| 473 static void |
|
| 474 silcpurple_chat_chauth(PurpleBlistNode *node, gpointer data) |
|
| 475 { |
|
| 476 PurpleChat *chat; |
|
| 477 PurpleConnection *gc; |
|
| 478 SilcPurple sg; |
|
| 479 |
|
| 480 g_return_if_fail(PURPLE_IS_CHAT(node)); |
|
| 481 |
|
| 482 chat = (PurpleChat *) node; |
|
| 483 gc = purple_account_get_connection(purple_chat_get_account(chat)); |
|
| 484 sg = purple_connection_get_protocol_data(gc); |
|
| 485 |
|
| 486 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", |
|
| 487 g_hash_table_lookup(purple_chat_get_components(chat), "channel"), |
|
| 488 "+C", NULL); |
|
| 489 } |
|
| 490 |
|
| 491 |
|
| 492 /************************** Channel Private Groups **************************/ |
|
| 493 |
|
| 494 /* Private groups are "virtual" channels. They are groups inside a channel. |
|
| 495 This is implemented by using channel private keys. By knowing a channel |
|
| 496 private key user becomes part of that group and is able to talk on that |
|
| 497 group. Other users, on the same channel, won't be able to see the |
|
| 498 messages of that group. It is possible to have multiple groups inside |
|
| 499 a channel - and thus having multiple private keys on the channel. */ |
|
| 500 |
|
| 501 typedef struct { |
|
| 502 SilcPurple sg; |
|
| 503 PurpleChat *c; |
|
| 504 const char *channel; |
|
| 505 } *SilcPurpleCharPrv; |
|
| 506 |
|
| 507 static void |
|
| 508 silcpurple_chat_prv_add(SilcPurpleCharPrv p, PurpleRequestFields *fields) |
|
| 509 { |
|
| 510 SilcPurple sg = p->sg; |
|
| 511 gchar *tmp; |
|
| 512 PurpleRequestField *f; |
|
| 513 const char *name, *passphrase, *alias; |
|
| 514 GHashTable *comp; |
|
| 515 PurpleGroup *g; |
|
| 516 PurpleChat *cn; |
|
| 517 |
|
| 518 f = purple_request_fields_get_field(fields, "name"); |
|
| 519 name = purple_request_field_string_get_value(f); |
|
| 520 if (!name) { |
|
| 521 silc_free(p); |
|
| 522 return; |
|
| 523 } |
|
| 524 f = purple_request_fields_get_field(fields, "passphrase"); |
|
| 525 passphrase = purple_request_field_string_get_value(f); |
|
| 526 f = purple_request_fields_get_field(fields, "alias"); |
|
| 527 alias = purple_request_field_string_get_value(f); |
|
| 528 |
|
| 529 /* Add private group to buddy list */ |
|
| 530 tmp = g_strdup_printf("%s [Private Group]", name); |
|
| 531 comp = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); |
|
| 532 g_hash_table_replace(comp, "channel", tmp); |
|
| 533 g_hash_table_replace(comp, "passphrase", g_strdup(passphrase)); |
|
| 534 |
|
| 535 cn = purple_chat_new(sg->account, alias, comp); |
|
| 536 g = purple_chat_get_group(p->c); |
|
| 537 purple_blist_add_chat(cn, g, (PurpleBlistNode *)p->c); |
|
| 538 |
|
| 539 /* Associate to a real channel */ |
|
| 540 purple_blist_node_set_string((PurpleBlistNode *)cn, "parentch", p->channel); |
|
| 541 |
|
| 542 /* Join the group */ |
|
| 543 silcpurple_chat_join(NULL, sg->gc, comp); |
|
| 544 |
|
| 545 silc_free(p); |
|
| 546 } |
|
| 547 |
|
| 548 static void |
|
| 549 silcpurple_chat_prv_cancel(SilcPurpleCharPrv p, PurpleRequestFields *fields) |
|
| 550 { |
|
| 551 silc_free(p); |
|
| 552 } |
|
| 553 |
|
| 554 static void |
|
| 555 silcpurple_chat_prv(PurpleBlistNode *node, gpointer data) |
|
| 556 { |
|
| 557 PurpleChat *chat; |
|
| 558 PurpleConnection *gc; |
|
| 559 SilcPurple sg; |
|
| 560 |
|
| 561 SilcPurpleCharPrv p; |
|
| 562 PurpleRequestFields *fields; |
|
| 563 PurpleRequestFieldGroup *g; |
|
| 564 PurpleRequestField *f; |
|
| 565 char tmp[512]; |
|
| 566 |
|
| 567 g_return_if_fail(PURPLE_IS_CHAT(node)); |
|
| 568 |
|
| 569 chat = (PurpleChat *) node; |
|
| 570 gc = purple_account_get_connection(purple_chat_get_account(chat)); |
|
| 571 sg = purple_connection_get_protocol_data(gc); |
|
| 572 |
|
| 573 p = silc_calloc(1, sizeof(*p)); |
|
| 574 if (!p) |
|
| 575 return; |
|
| 576 p->sg = sg; |
|
| 577 |
|
| 578 p->channel = g_hash_table_lookup(purple_chat_get_components(chat), "channel"); |
|
| 579 p->c = purple_blist_find_chat(sg->account, p->channel); |
|
| 580 |
|
| 581 fields = purple_request_fields_new(); |
|
| 582 |
|
| 583 g = purple_request_field_group_new(NULL); |
|
| 584 f = purple_request_field_string_new("name", _("Group Name"), |
|
| 585 NULL, FALSE); |
|
| 586 purple_request_field_group_add_field(g, f); |
|
| 587 |
|
| 588 f = purple_request_field_string_new("passphrase", _("Passphrase"), |
|
| 589 NULL, FALSE); |
|
| 590 purple_request_field_string_set_masked(f, TRUE); |
|
| 591 purple_request_field_group_add_field(g, f); |
|
| 592 |
|
| 593 f = purple_request_field_string_new("alias", _("Alias"), |
|
| 594 NULL, FALSE); |
|
| 595 purple_request_field_group_add_field(g, f); |
|
| 596 purple_request_fields_add_group(fields, g); |
|
| 597 |
|
| 598 g_snprintf(tmp, sizeof(tmp), |
|
| 599 _("Please enter the %s channel private group name and passphrase."), |
|
| 600 p->channel); |
|
| 601 purple_request_fields(gc, _("Add Channel Private Group"), NULL, tmp, fields, |
|
| 602 _("Add"), G_CALLBACK(silcpurple_chat_prv_add), |
|
| 603 _("Cancel"), G_CALLBACK(silcpurple_chat_prv_cancel), |
|
| 604 purple_request_cpar_from_connection(gc), p); |
|
| 605 } |
|
| 606 |
|
| 607 |
|
| 608 /****************************** Channel Modes ********************************/ |
|
| 609 |
|
| 610 static void |
|
| 611 silcpurple_chat_permanent_reset(PurpleBlistNode *node, gpointer data) |
|
| 612 { |
|
| 613 PurpleChat *chat; |
|
| 614 PurpleConnection *gc; |
|
| 615 SilcPurple sg; |
|
| 616 |
|
| 617 g_return_if_fail(PURPLE_IS_CHAT(node)); |
|
| 618 |
|
| 619 chat = (PurpleChat *) node; |
|
| 620 gc = purple_account_get_connection(purple_chat_get_account(chat)); |
|
| 621 sg = purple_connection_get_protocol_data(gc); |
|
| 622 |
|
| 623 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", |
|
| 624 g_hash_table_lookup(purple_chat_get_components(chat), "channel"), |
|
| 625 "-f", NULL); |
|
| 626 } |
|
| 627 |
|
| 628 static void |
|
| 629 silcpurple_chat_permanent(PurpleBlistNode *node, gpointer data) |
|
| 630 { |
|
| 631 PurpleChat *chat; |
|
| 632 PurpleConnection *gc; |
|
| 633 SilcPurple sg; |
|
| 634 const char *channel; |
|
| 635 |
|
| 636 g_return_if_fail(PURPLE_IS_CHAT(node)); |
|
| 637 |
|
| 638 chat = (PurpleChat *) node; |
|
| 639 gc = purple_account_get_connection(purple_chat_get_account(chat)); |
|
| 640 sg = purple_connection_get_protocol_data(gc); |
|
| 641 |
|
| 642 if (!sg->conn) |
|
| 643 return; |
|
| 644 |
|
| 645 /* XXX we should have ability to define which founder |
|
| 646 key to use. Now we use the user's own public key |
|
| 647 (default key). */ |
|
| 648 |
|
| 649 /* Call CMODE */ |
|
| 650 channel = g_hash_table_lookup(purple_chat_get_components(chat), "channel"); |
|
| 651 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", channel, |
|
| 652 "+f", NULL); |
|
| 653 } |
|
| 654 |
|
| 655 static void |
|
| 656 silcpurple_chat_ulimit_cb(PurpleKeyValuePair *s, const char *limit) |
|
| 657 { |
|
| 658 SilcPurple sg = s->value; |
|
| 659 SilcChannelEntry channel; |
|
| 660 guint ulimit = 0; |
|
| 661 |
|
| 662 channel = silc_client_get_channel(sg->client, sg->conn, s->key); |
|
| 663 if (!channel) |
|
| 664 return; |
|
| 665 if (limit) |
|
| 666 ulimit = strtoul(limit, NULL, 10); |
|
| 667 |
|
| 668 if (!limit || !(*limit) || *limit == '0') { |
|
| 669 if (!limit || ulimit != channel->user_limit) { |
|
| 670 silc_client_command_call(sg->client, sg->conn, NULL, |
|
| 671 "CMODE", s->key, "-l", NULL); |
|
| 672 } |
|
| 673 } else if (ulimit != channel->user_limit) { |
|
| 674 /* Call CMODE */ |
|
| 675 silc_client_command_call(sg->client, sg->conn, NULL, |
|
| 676 "CMODE", s->key, "+l", limit, NULL); |
|
| 677 } |
|
| 678 |
|
| 679 purple_key_value_pair_free(s); |
|
| 680 } |
|
| 681 |
|
| 682 static void |
|
| 683 silcpurple_chat_ulimit(PurpleBlistNode *node, gpointer data) |
|
| 684 { |
|
| 685 PurpleChat *chat; |
|
| 686 PurpleConnection *gc; |
|
| 687 SilcPurple sg; |
|
| 688 |
|
| 689 PurpleKeyValuePair *s; |
|
| 690 SilcChannelEntry channel; |
|
| 691 char *ch; |
|
| 692 char tmp[32]; |
|
| 693 |
|
| 694 g_return_if_fail(PURPLE_IS_CHAT(node)); |
|
| 695 |
|
| 696 chat = (PurpleChat *) node; |
|
| 697 gc = purple_account_get_connection(purple_chat_get_account(chat)); |
|
| 698 sg = purple_connection_get_protocol_data(gc); |
|
| 699 |
|
| 700 if (!sg->conn) |
|
| 701 return; |
|
| 702 |
|
| 703 ch = g_hash_table_lookup(purple_chat_get_components(chat), "channel"); |
|
| 704 channel = silc_client_get_channel(sg->client, sg->conn, ch); |
|
| 705 if (!channel) |
|
| 706 return; |
|
| 707 |
|
| 708 s = purple_key_value_pair_new(ch, sg); |
|
| 709 g_snprintf(tmp, sizeof(tmp), "%d", (int)channel->user_limit); |
|
| 710 purple_request_input(gc, _("User Limit"), NULL, |
|
| 711 _("Set user limit on channel. Set to zero to reset user limit."), |
|
| 712 tmp, FALSE, FALSE, NULL, |
|
| 713 _("OK"), G_CALLBACK(silcpurple_chat_ulimit_cb), |
|
| 714 _("Cancel"), G_CALLBACK(silcpurple_chat_ulimit_cb), |
|
| 715 purple_request_cpar_from_connection(gc), s); |
|
| 716 } |
|
| 717 |
|
| 718 static void |
|
| 719 silcpurple_chat_resettopic(PurpleBlistNode *node, gpointer data) |
|
| 720 { |
|
| 721 PurpleChat *chat; |
|
| 722 PurpleConnection *gc; |
|
| 723 SilcPurple sg; |
|
| 724 |
|
| 725 g_return_if_fail(PURPLE_IS_CHAT(node)); |
|
| 726 |
|
| 727 chat = (PurpleChat *) node; |
|
| 728 gc = purple_account_get_connection(purple_chat_get_account(chat)); |
|
| 729 sg = purple_connection_get_protocol_data(gc); |
|
| 730 |
|
| 731 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", |
|
| 732 g_hash_table_lookup(purple_chat_get_components(chat), "channel"), |
|
| 733 "-t", NULL); |
|
| 734 } |
|
| 735 |
|
| 736 static void |
|
| 737 silcpurple_chat_settopic(PurpleBlistNode *node, gpointer data) |
|
| 738 { |
|
| 739 PurpleChat *chat; |
|
| 740 PurpleConnection *gc; |
|
| 741 SilcPurple sg; |
|
| 742 |
|
| 743 g_return_if_fail(PURPLE_IS_CHAT(node)); |
|
| 744 |
|
| 745 chat = (PurpleChat *) node; |
|
| 746 gc = purple_account_get_connection(purple_chat_get_account(chat)); |
|
| 747 sg = purple_connection_get_protocol_data(gc); |
|
| 748 |
|
| 749 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", |
|
| 750 g_hash_table_lookup(purple_chat_get_components(chat), "channel"), |
|
| 751 "+t", NULL); |
|
| 752 } |
|
| 753 |
|
| 754 static void |
|
| 755 silcpurple_chat_resetprivate(PurpleBlistNode *node, gpointer data) |
|
| 756 { |
|
| 757 PurpleChat *chat; |
|
| 758 PurpleConnection *gc; |
|
| 759 SilcPurple sg; |
|
| 760 |
|
| 761 g_return_if_fail(PURPLE_IS_CHAT(node)); |
|
| 762 |
|
| 763 chat = (PurpleChat *) node; |
|
| 764 gc = purple_account_get_connection(purple_chat_get_account(chat)); |
|
| 765 sg = purple_connection_get_protocol_data(gc); |
|
| 766 |
|
| 767 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", |
|
| 768 g_hash_table_lookup(purple_chat_get_components(chat), "channel"), |
|
| 769 "-p", NULL); |
|
| 770 } |
|
| 771 |
|
| 772 static void |
|
| 773 silcpurple_chat_setprivate(PurpleBlistNode *node, gpointer data) |
|
| 774 { |
|
| 775 PurpleChat *chat; |
|
| 776 PurpleConnection *gc; |
|
| 777 SilcPurple sg; |
|
| 778 |
|
| 779 g_return_if_fail(PURPLE_IS_CHAT(node)); |
|
| 780 |
|
| 781 chat = (PurpleChat *) node; |
|
| 782 gc = purple_account_get_connection(purple_chat_get_account(chat)); |
|
| 783 sg = purple_connection_get_protocol_data(gc); |
|
| 784 |
|
| 785 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", |
|
| 786 g_hash_table_lookup(purple_chat_get_components(chat), "channel"), |
|
| 787 "+p", NULL); |
|
| 788 } |
|
| 789 |
|
| 790 static void |
|
| 791 silcpurple_chat_resetsecret(PurpleBlistNode *node, gpointer data) |
|
| 792 { |
|
| 793 PurpleChat *chat; |
|
| 794 PurpleConnection *gc; |
|
| 795 SilcPurple sg; |
|
| 796 |
|
| 797 g_return_if_fail(PURPLE_IS_CHAT(node)); |
|
| 798 |
|
| 799 chat = (PurpleChat *) node; |
|
| 800 gc = purple_account_get_connection(purple_chat_get_account(chat)); |
|
| 801 sg = purple_connection_get_protocol_data(gc); |
|
| 802 |
|
| 803 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", |
|
| 804 g_hash_table_lookup(purple_chat_get_components(chat), "channel"), |
|
| 805 "-s", NULL); |
|
| 806 } |
|
| 807 |
|
| 808 static void |
|
| 809 silcpurple_chat_setsecret(PurpleBlistNode *node, gpointer data) |
|
| 810 { |
|
| 811 PurpleChat *chat; |
|
| 812 PurpleConnection *gc; |
|
| 813 SilcPurple sg; |
|
| 814 |
|
| 815 g_return_if_fail(PURPLE_IS_CHAT(node)); |
|
| 816 |
|
| 817 chat = (PurpleChat *) node; |
|
| 818 gc = purple_account_get_connection(purple_chat_get_account(chat)); |
|
| 819 sg = purple_connection_get_protocol_data(gc); |
|
| 820 |
|
| 821 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", |
|
| 822 g_hash_table_lookup(purple_chat_get_components(chat), "channel"), |
|
| 823 "+s", NULL); |
|
| 824 } |
|
| 825 |
|
| 826 typedef struct { |
|
| 827 SilcPurple sg; |
|
| 828 SilcChannelEntry channel; |
|
| 829 } *SilcPurpleChatWb; |
|
| 830 |
|
| 831 static void |
|
| 832 silcpurple_chat_wb(PurpleBlistNode *node, gpointer data) |
|
| 833 { |
|
| 834 SilcPurpleChatWb wb = data; |
|
| 835 silcpurple_wb_init_ch(wb->sg, wb->channel); |
|
| 836 silc_free(wb); |
|
| 837 } |
|
| 838 |
|
| 839 GList *silcpurple_chat_menu(PurpleChat *chat) |
|
| 840 { |
|
| 841 GHashTable *components = purple_chat_get_components(chat); |
|
| 842 PurpleConnection *gc = purple_account_get_connection(purple_chat_get_account(chat)); |
|
| 843 SilcPurple sg = purple_connection_get_protocol_data(gc); |
|
| 844 SilcClientConnection conn = sg->conn; |
|
| 845 const char *chname = NULL; |
|
| 846 SilcChannelEntry channel = NULL; |
|
| 847 SilcChannelUser chu = NULL; |
|
| 848 SilcUInt32 mode = 0; |
|
| 849 |
|
| 850 GList *m = NULL; |
|
| 851 PurpleActionMenu *act; |
|
| 852 |
|
| 853 if (components) |
|
| 854 chname = g_hash_table_lookup(components, "channel"); |
|
| 855 if (!chname) |
|
| 856 return NULL; |
|
| 857 channel = silc_client_get_channel(sg->client, sg->conn, |
|
| 858 (char *)chname); |
|
| 859 if (channel) { |
|
| 860 chu = silc_client_on_channel(channel, conn->local_entry); |
|
| 861 if (chu) |
|
| 862 mode = chu->mode; |
|
| 863 } |
|
| 864 |
|
| 865 if (strstr(chname, "[Private Group]")) |
|
| 866 return NULL; |
|
| 867 |
|
| 868 act = purple_action_menu_new(_("Get Info"), |
|
| 869 G_CALLBACK(silcpurple_chat_getinfo_menu), |
|
| 870 NULL, NULL); |
|
| 871 m = g_list_append(m, act); |
|
| 872 |
|
| 873 if (chu) { |
|
| 874 act = purple_action_menu_new(_("Add Private Group"), |
|
| 875 G_CALLBACK(silcpurple_chat_prv), |
|
| 876 NULL, NULL); |
|
| 877 m = g_list_append(m, act); |
|
| 878 } |
|
| 879 |
|
| 880 if (chu && mode & SILC_CHANNEL_UMODE_CHANFO) { |
|
| 881 act = purple_action_menu_new(_("Channel Authentication"), |
|
| 882 G_CALLBACK(silcpurple_chat_chauth), |
|
| 883 NULL, NULL); |
|
| 884 m = g_list_append(m, act); |
|
| 885 |
|
| 886 if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) { |
|
| 887 act = purple_action_menu_new(_("Reset Permanent"), |
|
| 888 G_CALLBACK(silcpurple_chat_permanent_reset), |
|
| 889 NULL, NULL); |
|
| 890 m = g_list_append(m, act); |
|
| 891 } else { |
|
| 892 act = purple_action_menu_new(_("Set Permanent"), |
|
| 893 G_CALLBACK(silcpurple_chat_permanent), |
|
| 894 NULL, NULL); |
|
| 895 m = g_list_append(m, act); |
|
| 896 } |
|
| 897 } |
|
| 898 |
|
| 899 if (chu && mode & SILC_CHANNEL_UMODE_CHANOP) { |
|
| 900 act = purple_action_menu_new(_("Set User Limit"), |
|
| 901 G_CALLBACK(silcpurple_chat_ulimit), |
|
| 902 NULL, NULL); |
|
| 903 m = g_list_append(m, act); |
|
| 904 |
|
| 905 if (channel->mode & SILC_CHANNEL_MODE_TOPIC) { |
|
| 906 act = purple_action_menu_new(_("Reset Topic Restriction"), |
|
| 907 G_CALLBACK(silcpurple_chat_resettopic), |
|
| 908 NULL, NULL); |
|
| 909 m = g_list_append(m, act); |
|
| 910 } else { |
|
| 911 act = purple_action_menu_new(_("Set Topic Restriction"), |
|
| 912 G_CALLBACK(silcpurple_chat_settopic), |
|
| 913 NULL, NULL); |
|
| 914 m = g_list_append(m, act); |
|
| 915 } |
|
| 916 |
|
| 917 if (channel->mode & SILC_CHANNEL_MODE_PRIVATE) { |
|
| 918 act = purple_action_menu_new(_("Reset Private Channel"), |
|
| 919 G_CALLBACK(silcpurple_chat_resetprivate), |
|
| 920 NULL, NULL); |
|
| 921 m = g_list_append(m, act); |
|
| 922 } else { |
|
| 923 act = purple_action_menu_new(_("Set Private Channel"), |
|
| 924 G_CALLBACK(silcpurple_chat_setprivate), |
|
| 925 NULL, NULL); |
|
| 926 m = g_list_append(m, act); |
|
| 927 } |
|
| 928 |
|
| 929 if (channel->mode & SILC_CHANNEL_MODE_SECRET) { |
|
| 930 act = purple_action_menu_new(_("Reset Secret Channel"), |
|
| 931 G_CALLBACK(silcpurple_chat_resetsecret), |
|
| 932 NULL, NULL); |
|
| 933 m = g_list_append(m, act); |
|
| 934 } else { |
|
| 935 act = purple_action_menu_new(_("Set Secret Channel"), |
|
| 936 G_CALLBACK(silcpurple_chat_setsecret), |
|
| 937 NULL, NULL); |
|
| 938 m = g_list_append(m, act); |
|
| 939 } |
|
| 940 } |
|
| 941 |
|
| 942 if (chu && channel) { |
|
| 943 SilcPurpleChatWb wb; |
|
| 944 wb = silc_calloc(1, sizeof(*wb)); |
|
| 945 wb->sg = sg; |
|
| 946 wb->channel = channel; |
|
| 947 act = purple_action_menu_new(_("Draw On Whiteboard"), |
|
| 948 G_CALLBACK(silcpurple_chat_wb), |
|
| 949 (void *)wb, NULL); |
|
| 950 m = g_list_append(m, act); |
|
| 951 } |
|
| 952 |
|
| 953 return m; |
|
| 954 } |
|
| 955 |
|
| 956 |
|
| 957 /******************************* Joining Etc. ********************************/ |
|
| 958 |
|
| 959 char *silcpurple_get_chat_name(PurpleProtocolChat *protocol_chat, GHashTable *data) |
|
| 960 { |
|
| 961 return g_strdup(g_hash_table_lookup(data, "channel")); |
|
| 962 } |
|
| 963 |
|
| 964 void silcpurple_chat_join(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, GHashTable *data) |
|
| 965 { |
|
| 966 SilcPurple sg = purple_connection_get_protocol_data(gc); |
|
| 967 SilcClient client = sg->client; |
|
| 968 SilcClientConnection conn = sg->conn; |
|
| 969 const char *channel, *passphrase, *parentch; |
|
| 970 |
|
| 971 if (!conn) |
|
| 972 return; |
|
| 973 |
|
| 974 channel = g_hash_table_lookup(data, "channel"); |
|
| 975 passphrase = g_hash_table_lookup(data, "passphrase"); |
|
| 976 |
|
| 977 /* Check if we are joining a private group. Handle it |
|
| 978 purely locally as it's not a real channel */ |
|
| 979 if (strstr(channel, "[Private Group]")) { |
|
| 980 SilcChannelEntry channel_entry; |
|
| 981 SilcChannelPrivateKey key; |
|
| 982 PurpleChat *c; |
|
| 983 SilcPurplePrvgrp grp; |
|
| 984 |
|
| 985 c = purple_blist_find_chat(sg->account, channel); |
|
| 986 parentch = purple_blist_node_get_string((PurpleBlistNode *)c, "parentch"); |
|
| 987 if (!parentch) |
|
| 988 return; |
|
| 989 |
|
| 990 channel_entry = silc_client_get_channel(sg->client, sg->conn, |
|
| 991 (char *)parentch); |
|
| 992 if (!channel_entry || |
|
| 993 !silc_client_on_channel(channel_entry, sg->conn->local_entry)) { |
|
| 994 char tmp[512]; |
|
| 995 g_snprintf(tmp, sizeof(tmp), |
|
| 996 _("You have to join the %s channel before you are " |
|
| 997 "able to join the private group"), parentch); |
|
| 998 purple_notify_error(gc, _("Join Private Group"), |
|
| 999 _("Cannot join private group"), tmp, |
|
| 1000 purple_request_cpar_from_connection(gc)); |
|
| 1001 return; |
|
| 1002 } |
|
| 1003 |
|
| 1004 /* Add channel private key */ |
|
| 1005 if (!silc_client_add_channel_private_key(client, conn, |
|
| 1006 channel_entry, channel, |
|
| 1007 NULL, NULL, |
|
| 1008 (unsigned char *)passphrase, |
|
| 1009 strlen(passphrase), &key)) |
|
| 1010 return; |
|
| 1011 |
|
| 1012 /* Join the group */ |
|
| 1013 grp = silc_calloc(1, sizeof(*grp)); |
|
| 1014 if (!grp) |
|
| 1015 return; |
|
| 1016 grp->id = ++sg->channel_ids + SILCPURPLE_PRVGRP; |
|
| 1017 grp->chid = SILC_PTR_TO_32(channel_entry->context); |
|
| 1018 grp->parentch = parentch; |
|
| 1019 grp->channel = channel; |
|
| 1020 grp->key = key; |
|
| 1021 sg->grps = g_list_append(sg->grps, grp); |
|
| 1022 purple_serv_got_joined_chat(gc, grp->id, channel); |
|
| 1023 return; |
|
| 1024 } |
|
| 1025 |
|
| 1026 /* XXX We should have other properties here as well: |
|
| 1027 1. whether to try to authenticate to the channel |
|
| 1028 1a. with default key, |
|
| 1029 1b. with specific key. |
|
| 1030 2. whether to try to authenticate to become founder. |
|
| 1031 2a. with default key, |
|
| 1032 2b. with specific key. |
|
| 1033 |
|
| 1034 Since now such variety is not possible in the join dialog |
|
| 1035 we always use -founder and -auth options, which try to |
|
| 1036 do both 1 and 2 with default keys. */ |
|
| 1037 |
|
| 1038 /* Call JOIN */ |
|
| 1039 if ((passphrase != NULL) && (*passphrase != '\0')) |
|
| 1040 silc_client_command_call(client, conn, NULL, "JOIN", |
|
| 1041 channel, passphrase, "-auth", "-founder", NULL); |
|
| 1042 else |
|
| 1043 silc_client_command_call(client, conn, NULL, "JOIN", |
|
| 1044 channel, "-auth", "-founder", NULL); |
|
| 1045 } |
|
| 1046 |
|
| 1047 void silcpurple_chat_invite(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id, const char *msg, |
|
| 1048 const char *name) |
|
| 1049 { |
|
| 1050 SilcPurple sg = purple_connection_get_protocol_data(gc); |
|
| 1051 SilcClient client = sg->client; |
|
| 1052 SilcClientConnection conn = sg->conn; |
|
| 1053 SilcHashTableList htl; |
|
| 1054 SilcChannelUser chu; |
|
| 1055 gboolean found = FALSE; |
|
| 1056 |
|
| 1057 if (!conn) |
|
| 1058 return; |
|
| 1059 |
|
| 1060 /* See if we are inviting on a private group. Invite |
|
| 1061 to the actual channel */ |
|
| 1062 if (id > SILCPURPLE_PRVGRP) { |
|
| 1063 GList *l; |
|
| 1064 SilcPurplePrvgrp prv; |
|
| 1065 |
|
| 1066 for (l = sg->grps; l; l = l->next) |
|
| 1067 if (((SilcPurplePrvgrp)l->data)->id == (gulong)id) |
|
| 1068 break; |
|
| 1069 if (!l) |
|
| 1070 return; |
|
| 1071 prv = l->data; |
|
| 1072 id = prv->chid; |
|
| 1073 } |
|
| 1074 |
|
| 1075 /* Find channel by id */ |
|
| 1076 silc_hash_table_list(conn->local_entry->channels, &htl); |
|
| 1077 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { |
|
| 1078 if (SILC_PTR_TO_32(chu->channel->context) == (gulong)id ) { |
|
| 1079 found = TRUE; |
|
| 1080 break; |
|
| 1081 } |
|
| 1082 } |
|
| 1083 silc_hash_table_list_reset(&htl); |
|
| 1084 if (!found) |
|
| 1085 return; |
|
| 1086 |
|
| 1087 /* Call INVITE */ |
|
| 1088 silc_client_command_call(client, conn, NULL, "INVITE", |
|
| 1089 chu->channel->channel_name, |
|
| 1090 name, NULL); |
|
| 1091 } |
|
| 1092 |
|
| 1093 void silcpurple_chat_leave(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id) |
|
| 1094 { |
|
| 1095 SilcPurple sg = purple_connection_get_protocol_data(gc); |
|
| 1096 SilcClient client = sg->client; |
|
| 1097 SilcClientConnection conn = sg->conn; |
|
| 1098 SilcHashTableList htl; |
|
| 1099 SilcChannelUser chu; |
|
| 1100 gboolean found = FALSE; |
|
| 1101 GList *l; |
|
| 1102 SilcPurplePrvgrp prv; |
|
| 1103 |
|
| 1104 if (!conn) |
|
| 1105 return; |
|
| 1106 |
|
| 1107 /* See if we are leaving a private group */ |
|
| 1108 if (id > SILCPURPLE_PRVGRP) { |
|
| 1109 SilcChannelEntry channel; |
|
| 1110 |
|
| 1111 for (l = sg->grps; l; l = l->next) |
|
| 1112 if (((SilcPurplePrvgrp)l->data)->id == (gulong)id) |
|
| 1113 break; |
|
| 1114 if (!l) |
|
| 1115 return; |
|
| 1116 prv = l->data; |
|
| 1117 channel = silc_client_get_channel(sg->client, sg->conn, |
|
| 1118 (char *)prv->parentch); |
|
| 1119 if (!channel) |
|
| 1120 return; |
|
| 1121 silc_client_del_channel_private_key(client, conn, |
|
| 1122 channel, prv->key); |
|
| 1123 silc_free(prv); |
|
| 1124 sg->grps = g_list_delete_link(sg->grps, l); |
|
| 1125 purple_serv_got_chat_left(gc, id); |
|
| 1126 return; |
|
| 1127 } |
|
| 1128 |
|
| 1129 /* Find channel by id */ |
|
| 1130 silc_hash_table_list(conn->local_entry->channels, &htl); |
|
| 1131 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { |
|
| 1132 if (SILC_PTR_TO_32(chu->channel->context) == (gulong)id ) { |
|
| 1133 found = TRUE; |
|
| 1134 break; |
|
| 1135 } |
|
| 1136 } |
|
| 1137 silc_hash_table_list_reset(&htl); |
|
| 1138 if (!found) |
|
| 1139 return; |
|
| 1140 |
|
| 1141 /* Call LEAVE */ |
|
| 1142 silc_client_command_call(client, conn, NULL, "LEAVE", |
|
| 1143 chu->channel->channel_name, NULL); |
|
| 1144 |
|
| 1145 purple_serv_got_chat_left(gc, id); |
|
| 1146 |
|
| 1147 /* Leave from private groups on this channel as well */ |
|
| 1148 for (l = sg->grps; l; l = l->next) |
|
| 1149 if (((SilcPurplePrvgrp)l->data)->chid == (gulong)id) { |
|
| 1150 prv = l->data; |
|
| 1151 silc_client_del_channel_private_key(client, conn, |
|
| 1152 chu->channel, |
|
| 1153 prv->key); |
|
| 1154 purple_serv_got_chat_left(gc, prv->id); |
|
| 1155 silc_free(prv); |
|
| 1156 sg->grps = g_list_delete_link(sg->grps, l); |
|
| 1157 if (!sg->grps) |
|
| 1158 break; |
|
| 1159 } |
|
| 1160 } |
|
| 1161 |
|
| 1162 int silcpurple_chat_send(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id, PurpleMessage *pmsg) |
|
| 1163 { |
|
| 1164 SilcPurple sg = purple_connection_get_protocol_data(gc); |
|
| 1165 SilcClient client = sg->client; |
|
| 1166 SilcClientConnection conn = sg->conn; |
|
| 1167 SilcHashTableList htl; |
|
| 1168 SilcChannelUser chu; |
|
| 1169 SilcChannelEntry channel = NULL; |
|
| 1170 SilcChannelPrivateKey key = NULL; |
|
| 1171 SilcMessageFlags flags; |
|
| 1172 int ret = 0; |
|
| 1173 const gchar *msg = purple_message_get_contents(pmsg); |
|
| 1174 char *msg2, *tmp; |
|
| 1175 gboolean found = FALSE; |
|
| 1176 gboolean sign = purple_account_get_bool(sg->account, "sign-verify", FALSE); |
|
| 1177 SilcDList list; |
|
| 1178 PurpleMessageFlags msgflags = purple_message_get_flags(pmsg); |
|
| 1179 |
|
| 1180 if (!msg || !conn) |
|
| 1181 return 0; |
|
| 1182 |
|
| 1183 flags = SILC_MESSAGE_FLAG_UTF8; |
|
| 1184 |
|
| 1185 tmp = msg2 = purple_unescape_html(msg); |
|
| 1186 |
|
| 1187 if (!g_ascii_strncasecmp(msg2, "/me ", 4)) |
|
| 1188 { |
|
| 1189 msg2 += 4; |
|
| 1190 if (!*msg2) { |
|
| 1191 g_free(tmp); |
|
| 1192 return 0; |
|
| 1193 } |
|
| 1194 flags |= SILC_MESSAGE_FLAG_ACTION; |
|
| 1195 } else if (strlen(msg) > 1 && msg[0] == '/') { |
|
| 1196 if (!silc_client_command_call(client, conn, msg + 1)) { |
|
| 1197 purple_notify_error(gc, _("Call Command"), |
|
| 1198 _("Cannot call command"), _("Unknown command"), |
|
| 1199 purple_request_cpar_from_connection(gc)); |
|
| 1200 } |
|
| 1201 g_free(tmp); |
|
| 1202 return 0; |
|
| 1203 } |
|
| 1204 |
|
| 1205 |
|
| 1206 if (sign) |
|
| 1207 flags |= SILC_MESSAGE_FLAG_SIGNED; |
|
| 1208 |
|
| 1209 /* Get the channel private key if we are sending on |
|
| 1210 private group */ |
|
| 1211 if (id > SILCPURPLE_PRVGRP) { |
|
| 1212 GList *l; |
|
| 1213 SilcPurplePrvgrp prv; |
|
| 1214 |
|
| 1215 for (l = sg->grps; l; l = l->next) |
|
| 1216 if (((SilcPurplePrvgrp)l->data)->id == (gulong)id) |
|
| 1217 break; |
|
| 1218 if (!l) { |
|
| 1219 g_free(tmp); |
|
| 1220 return 0; |
|
| 1221 } |
|
| 1222 prv = l->data; |
|
| 1223 channel = silc_client_get_channel(sg->client, sg->conn, |
|
| 1224 (char *)prv->parentch); |
|
| 1225 if (!channel) { |
|
| 1226 g_free(tmp); |
|
| 1227 return 0; |
|
| 1228 } |
|
| 1229 key = prv->key; |
|
| 1230 } |
|
| 1231 |
|
| 1232 if (!channel) { |
|
| 1233 /* Find channel by id */ |
|
| 1234 silc_hash_table_list(conn->local_entry->channels, &htl); |
|
| 1235 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { |
|
| 1236 if (SILC_PTR_TO_32(chu->channel->context) == (gulong)id ) { |
|
| 1237 found = TRUE; |
|
| 1238 break; |
|
| 1239 } |
|
| 1240 } |
|
| 1241 silc_hash_table_list_reset(&htl); |
|
| 1242 if (!found) { |
|
| 1243 g_free(tmp); |
|
| 1244 return 0; |
|
| 1245 } |
|
| 1246 channel = chu->channel; |
|
| 1247 } |
|
| 1248 |
|
| 1249 /* Check for images */ |
|
| 1250 if (msgflags & PURPLE_MESSAGE_IMAGES) { |
|
| 1251 list = silcpurple_image_message(msg, &flags); |
|
| 1252 if (list) { |
|
| 1253 /* Send one or more MIME message. If more than one, they |
|
| 1254 are MIME fragments due to over large message */ |
|
| 1255 SilcBuffer buf; |
|
| 1256 |
|
| 1257 silc_dlist_start(list); |
|
| 1258 while ((buf = silc_dlist_get(list)) != SILC_LIST_END) |
|
| 1259 ret = |
|
| 1260 silc_client_send_channel_message(client, conn, |
|
| 1261 channel, key, |
|
| 1262 flags, sg->sha1hash, |
|
| 1263 buf->data, |
|
| 1264 silc_buffer_len(buf)); |
|
| 1265 silc_mime_partial_free(list); |
|
| 1266 g_free(tmp); |
|
| 1267 |
|
| 1268 if (ret) |
|
| 1269 purple_serv_got_chat_in(gc, id, purple_connection_get_display_name(gc), msgflags, msg, time(NULL)); |
|
| 1270 return ret; |
|
| 1271 } |
|
| 1272 } |
|
| 1273 |
|
| 1274 /* Send channel message */ |
|
| 1275 ret = silc_client_send_channel_message(client, conn, channel, key, |
|
| 1276 flags, sg->sha1hash, |
|
| 1277 (unsigned char *)msg2, |
|
| 1278 strlen(msg2)); |
|
| 1279 if (ret) { |
|
| 1280 purple_serv_got_chat_in(gc, id, purple_connection_get_display_name(gc), msgflags, msg, |
|
| 1281 time(NULL)); |
|
| 1282 } |
|
| 1283 g_free(tmp); |
|
| 1284 |
|
| 1285 return ret; |
|
| 1286 } |
|
| 1287 |
|
| 1288 void silcpurple_chat_set_topic(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id, const char *topic) |
|
| 1289 { |
|
| 1290 SilcPurple sg = purple_connection_get_protocol_data(gc); |
|
| 1291 SilcClient client = sg->client; |
|
| 1292 SilcClientConnection conn = sg->conn; |
|
| 1293 SilcHashTableList htl; |
|
| 1294 SilcChannelUser chu; |
|
| 1295 gboolean found = FALSE; |
|
| 1296 |
|
| 1297 if (!conn) |
|
| 1298 return; |
|
| 1299 |
|
| 1300 /* See if setting topic on private group. Set it |
|
| 1301 on the actual channel */ |
|
| 1302 if (id > SILCPURPLE_PRVGRP) { |
|
| 1303 GList *l; |
|
| 1304 SilcPurplePrvgrp prv; |
|
| 1305 |
|
| 1306 for (l = sg->grps; l; l = l->next) |
|
| 1307 if (((SilcPurplePrvgrp)l->data)->id == (gulong)id) |
|
| 1308 break; |
|
| 1309 if (!l) |
|
| 1310 return; |
|
| 1311 prv = l->data; |
|
| 1312 id = prv->chid; |
|
| 1313 } |
|
| 1314 |
|
| 1315 /* Find channel by id */ |
|
| 1316 silc_hash_table_list(conn->local_entry->channels, &htl); |
|
| 1317 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { |
|
| 1318 if (SILC_PTR_TO_32(chu->channel->context) == (gulong)id ) { |
|
| 1319 found = TRUE; |
|
| 1320 break; |
|
| 1321 } |
|
| 1322 } |
|
| 1323 silc_hash_table_list_reset(&htl); |
|
| 1324 if (!found) |
|
| 1325 return; |
|
| 1326 |
|
| 1327 /* Call TOPIC */ |
|
| 1328 silc_client_command_call(client, conn, NULL, "TOPIC", |
|
| 1329 chu->channel->channel_name, topic, NULL); |
|
| 1330 } |
|
| 1331 |
|
| 1332 PurpleRoomlist * |
|
| 1333 silcpurple_roomlist_get_list(PurpleProtocolRoomlist *protocol_roomlist, |
|
| 1334 PurpleConnection *gc) |
|
| 1335 { |
|
| 1336 SilcPurple sg = purple_connection_get_protocol_data(gc); |
|
| 1337 SilcClient client = sg->client; |
|
| 1338 SilcClientConnection conn = sg->conn; |
|
| 1339 |
|
| 1340 if (!conn) |
|
| 1341 return NULL; |
|
| 1342 |
|
| 1343 if (sg->roomlist) |
|
| 1344 g_object_unref(sg->roomlist); |
|
| 1345 |
|
| 1346 sg->roomlist_cancelled = FALSE; |
|
| 1347 |
|
| 1348 sg->roomlist = purple_roomlist_new(purple_connection_get_account(gc)); |
|
| 1349 |
|
| 1350 /* Call LIST */ |
|
| 1351 silc_client_command_call(client, conn, "LIST"); |
|
| 1352 |
|
| 1353 purple_roomlist_set_in_progress(sg->roomlist, TRUE); |
|
| 1354 |
|
| 1355 return sg->roomlist; |
|
| 1356 } |
|
| 1357 |
|
| 1358 void |
|
| 1359 silcpurple_roomlist_cancel(PurpleProtocolRoomlist *protocol_roomlist, |
|
| 1360 PurpleRoomlist *list) |
|
| 1361 { |
|
| 1362 PurpleAccount *account = purple_roomlist_get_account(list); |
|
| 1363 PurpleConnection *gc = purple_account_get_connection(account); |
|
| 1364 SilcPurple sg; |
|
| 1365 |
|
| 1366 if (!gc) |
|
| 1367 return; |
|
| 1368 sg = purple_connection_get_protocol_data(gc); |
|
| 1369 |
|
| 1370 purple_roomlist_set_in_progress(list, FALSE); |
|
| 1371 if (sg->roomlist == list) { |
|
| 1372 g_object_unref(sg->roomlist); |
|
| 1373 sg->roomlist = NULL; |
|
| 1374 sg->roomlist_cancelled = TRUE; |
|
| 1375 } |
|
| 1376 } |
|