comparison libpurple/protocols/silc/silc.c @ 17806:980a104267da

Patch from Pekka Riikonen to update the SILC protocol plugin to work with SILC Toolkit 1.1 I added the fallback to SILC Toolkit 1.0 support (silc10 protocol directory) and configure.ac adjustments, any problems with this are 100% my fault.
author Stu Tomlinson <stu@nosnilmot.com>
date Sat, 09 Jun 2007 17:31:28 +0000
parents 0f4a562b38d1
children b142c090eaf7
comparison
equal deleted inserted replaced
17805:ba1b50f114f6 17806:980a104267da
2 2
3 silcpurple.c 3 silcpurple.c
4 4
5 Author: Pekka Riikonen <priikone@silcnet.org> 5 Author: Pekka Riikonen <priikone@silcnet.org>
6 6
7 Copyright (C) 2004 - 2005 Pekka Riikonen 7 Copyright (C) 2004 - 2007 Pekka Riikonen
8 8
9 This program is free software; you can redistribute it and/or modify 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 10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License. 11 the Free Software Foundation; version 2 of the License.
12 12
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details. 16 GNU General Public License for more details.
17 17
18 */ 18 */
19 19
20 #include "silcincludes.h" 20 #include "silc.h"
21 #include "silcclient.h" 21 #include "silcclient.h"
22 #include "silcpurple.h" 22 #include "silcpurple.h"
23 #include "version.h" 23 #include "version.h"
24 #include "wb.h" 24 #include "wb.h"
25 25
26 extern SilcClientOperations ops; 26 extern SilcClientOperations ops;
27 static PurplePlugin *silc_plugin = NULL; 27 static PurplePlugin *silc_plugin = NULL;
28
29 /* Error log message callback */
30
31 static SilcBool silcpurple_log_error(SilcLogType type, char *message,
32 void *context)
33 {
34 silc_say(NULL, NULL, SILC_CLIENT_MESSAGE_ERROR, message);
35 return TRUE;
36 }
28 37
29 static const char * 38 static const char *
30 silcpurple_list_icon(PurpleAccount *a, PurpleBuddy *b) 39 silcpurple_list_icon(PurpleAccount *a, PurpleBuddy *b)
31 { 40 {
32 return (const char *)"silc"; 41 return (const char *)"silc";
100 109
101 /* Send UMODE */ 110 /* Send UMODE */
102 idp = silc_id_payload_encode(sg->conn->local_id, SILC_ID_CLIENT); 111 idp = silc_id_payload_encode(sg->conn->local_id, SILC_ID_CLIENT);
103 SILC_PUT32_MSB(mode, mb); 112 SILC_PUT32_MSB(mode, mb);
104 silc_client_command_send(sg->client, sg->conn, SILC_COMMAND_UMODE, 113 silc_client_command_send(sg->client, sg->conn, SILC_COMMAND_UMODE,
105 ++sg->conn->cmd_ident, 2, 114 silcpurple_command_reply, NULL, 2,
106 1, idp->data, idp->len, 115 1, idp->data, silc_buffer_len(idp),
107 2, mb, sizeof(mb)); 116 2, mb, sizeof(mb));
108 silc_buffer_free(idp); 117 silc_buffer_free(idp);
109 } 118 }
110 119
111 120
113 122
114 static void 123 static void
115 silcpurple_keepalive(PurpleConnection *gc) 124 silcpurple_keepalive(PurpleConnection *gc)
116 { 125 {
117 SilcPurple sg = gc->proto_data; 126 SilcPurple sg = gc->proto_data;
118 silc_client_send_packet(sg->client, sg->conn, SILC_PACKET_HEARTBEAT, 127 silc_packet_send(sg->conn->stream, SILC_PACKET_HEARTBEAT, 0,
119 NULL, 0); 128 NULL, 0);
120 } 129 }
121 130
122 static gboolean 131 static gboolean
123 silcpurple_scheduler(gpointer *context) 132 silcpurple_scheduler(gpointer *context)
124 { 133 {
125 SilcPurple sg = (SilcPurple)context; 134 SilcClient client = (SilcClient)context;
126 silc_client_run_one(sg->client); 135 silc_client_run_one(client);
127 return TRUE; 136 return TRUE;
128 } 137 }
129 138
130 static void 139 static void
131 silcpurple_nickname_parse(const char *nickname, 140 silcpurple_connect_cb(SilcClient client, SilcClientConnection conn,
132 char **ret_nickname) 141 SilcClientConnectionStatus status, SilcStatus error,
133 { 142 const char *message, void *context)
134 silc_parse_userfqdn(nickname, ret_nickname, NULL); 143 {
135 } 144 PurpleConnection *gc = context;
136
137 static void
138 silcpurple_login_connected(gpointer data, gint source, const gchar *error_message)
139 {
140 PurpleConnection *gc = data;
141 SilcPurple sg; 145 SilcPurple sg;
142 SilcClient client; 146 gboolean reject_watch, block_invites, block_ims;
143 SilcClientConnection conn;
144 PurpleAccount *account;
145 SilcClientConnectionParams params;
146 const char *dfile;
147
148 g_return_if_fail(gc != NULL);
149 147
150 sg = gc->proto_data; 148 sg = gc->proto_data;
151 149
152 if (source < 0) { 150 switch (status) {
153 purple_connection_error(gc, _("Connection failed")); 151 case SILC_CLIENT_CONN_SUCCESS:
154 return; 152 case SILC_CLIENT_CONN_SUCCESS_RESUME:
155 } 153 sg->conn = conn;
156 154
157 client = sg->client; 155 /* Connection created successfully */
158 account = sg->account; 156 purple_connection_set_state(gc, PURPLE_CONNECTED);
159 157
160 /* Get session detachment data, if available */ 158 /* Send the server our buddy list */
161 memset(&params, 0, sizeof(params)); 159 silcpurple_send_buddylist(gc);
162 dfile = silcpurple_session_file(purple_account_get_username(sg->account)); 160
163 params.detach_data = (unsigned char *)silc_file_readfile(dfile, &params.detach_data_len); 161 g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
164 if (params.detach_data) 162
165 params.detach_data[params.detach_data_len] = 0; 163 /* Send any UMODEs configured for account */
166 164 reject_watch = purple_account_get_bool(sg->account, "reject-watch", FALSE);
167 /* Add connection to SILC client library */ 165 block_invites = purple_account_get_bool(sg->account, "block-invites", FALSE);
168 conn = silc_client_add_connection( 166 block_ims = purple_account_get_bool(sg->account, "block-ims", FALSE);
169 sg->client, &params, 167 if (reject_watch || block_invites || block_ims) {
170 (char *)purple_account_get_string(account, "server", 168 char m[5];
171 "silc.silcnet.org"), 169 g_snprintf(m, sizeof(m), "+%s%s%s",
172 purple_account_get_int(account, "port", 706), sg); 170 reject_watch ? "w" : "",
173 if (!conn) { 171 block_invites ? "I" : "",
174 purple_connection_error(gc, _("Cannot initialize SILC Client connection")); 172 block_ims ? "P" : "");
175 gc->proto_data = NULL; 173 silc_client_command_call(sg->client, sg->conn, NULL,
176 return; 174 "UMODE", m, NULL);
177 } 175 }
178 sg->conn = conn; 176
179 177 /* Set default attributes */
180 /* Progress */ 178 if (!purple_account_get_bool(sg->account, "reject-attrs", FALSE)) {
181 if (params.detach_data) { 179 SilcUInt32 mask;
182 purple_connection_update_progress(gc, _("Resuming session"), 2, 5); 180 char tz[16];
183 sg->resuming = TRUE;
184 } else {
185 purple_connection_update_progress(gc, _("Performing key exchange"), 2, 5);
186 }
187
188 /* Perform SILC Key Exchange. The "silc_connected" will be called
189 eventually. */
190 silc_client_start_key_exchange(sg->client, sg->conn, source);
191
192 /* Set default attributes */
193 if (!purple_account_get_bool(account, "reject-attrs", FALSE)) {
194 SilcUInt32 mask;
195 const char *tmp;
196 #ifdef SILC_ATTRIBUTE_USER_ICON 181 #ifdef SILC_ATTRIBUTE_USER_ICON
197 PurpleStoredImage *img; 182 PurpleStoredImage *img;
198 #endif 183 #endif
199 #ifdef HAVE_SYS_UTSNAME_H 184 #ifdef HAVE_SYS_UTSNAME_H
200 struct utsname u; 185 struct utsname u;
201 #endif 186 #endif
202 187
203 mask = SILC_ATTRIBUTE_MOOD_NORMAL; 188 mask = SILC_ATTRIBUTE_MOOD_NORMAL;
204 silc_client_attribute_add(client, conn, 189 silc_client_attribute_add(client, conn,
205 SILC_ATTRIBUTE_STATUS_MOOD, 190 SILC_ATTRIBUTE_STATUS_MOOD,
206 SILC_32_TO_PTR(mask), 191 SILC_32_TO_PTR(mask),
207 sizeof(SilcUInt32)); 192 sizeof(SilcUInt32));
208 mask = SILC_ATTRIBUTE_CONTACT_CHAT; 193 mask = SILC_ATTRIBUTE_CONTACT_CHAT;
209 silc_client_attribute_add(client, conn, 194 silc_client_attribute_add(client, conn,
210 SILC_ATTRIBUTE_PREFERRED_CONTACT, 195 SILC_ATTRIBUTE_PREFERRED_CONTACT,
211 SILC_32_TO_PTR(mask), 196 SILC_32_TO_PTR(mask),
212 sizeof(SilcUInt32)); 197 sizeof(SilcUInt32));
213 #ifdef HAVE_SYS_UTSNAME_H 198 #ifdef HAVE_SYS_UTSNAME_H
214 if (!uname(&u)) { 199 if (!uname(&u)) {
215 SilcAttributeObjDevice dev; 200 SilcAttributeObjDevice dev;
216 memset(&dev, 0, sizeof(dev)); 201 memset(&dev, 0, sizeof(dev));
217 dev.type = SILC_ATTRIBUTE_DEVICE_COMPUTER; 202 dev.type = SILC_ATTRIBUTE_DEVICE_COMPUTER;
218 dev.version = u.release; 203 dev.version = u.release;
219 dev.model = u.sysname; 204 dev.model = u.sysname;
220 silc_client_attribute_add(client, conn, 205 silc_client_attribute_add(client, conn,
221 SILC_ATTRIBUTE_DEVICE_INFO, 206 SILC_ATTRIBUTE_DEVICE_INFO,
222 (void *)&dev, sizeof(dev)); 207 (void *)&dev, sizeof(dev));
208 }
209 #endif
210 silc_timezone(tz, sizeof(tz));
211 silc_client_attribute_add(client, conn,
212 SILC_ATTRIBUTE_TIMEZONE,
213 (void *)tz, strlen(tz));
214
215 #ifdef SILC_ATTRIBUTE_USER_ICON
216 /* Set our buddy icon */
217 img = purple_buddy_icons_find_account_icon(sg->account);
218 silcpurple_buddy_set_icon(gc, img);
219 purple_imgstore_unref(img);
220 #endif
223 } 221 }
224 #endif 222
225 #ifdef _WIN32 223 return;
226 tmp = _tzname[0]; 224 break;
227 #else 225
228 tmp = tzname[0]; 226 case SILC_CLIENT_CONN_DISCONNECTED:
229 #endif 227 /* Disconnected */
230 silc_client_attribute_add(client, conn, 228 if (sg->resuming && !sg->detaching)
231 SILC_ATTRIBUTE_TIMEZONE, 229 g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
232 (void *)tmp, strlen(tmp)); 230
233 231 /* Close the connection */
234 #ifdef SILC_ATTRIBUTE_USER_ICON 232 if (!sg->detaching)
235 /* Set our buddy icon */ 233 purple_connection_error(gc, _("Disconnected by server"));
236 img = purple_buddy_icons_find_account_icon(account); 234 else
237 silcpurple_buddy_set_icon(gc, img); 235 /* TODO: Does this work correctly? Maybe we need to set wants_to_die? */
238 purple_imgstore_unref(img); 236 purple_account_disconnect(purple_connection_get_account(gc));
239 #endif 237 break;
240 } 238
241 239 case SILC_CLIENT_CONN_ERROR:
242 silc_free(params.detach_data); 240 purple_connection_error(gc, _("Error during connecting to SILC Server"));
243 } 241 g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
244 242 break;
245 static void 243
246 silcpurple_login(PurpleAccount *account) 244 case SILC_CLIENT_CONN_ERROR_KE:
247 { 245 purple_connection_error(gc, _("Key Exchange failed"));
246 break;
247
248 case SILC_CLIENT_CONN_ERROR_AUTH:
249 purple_connection_error(gc, _("Authentication failed"));
250 break;
251
252 case SILC_CLIENT_CONN_ERROR_RESUME:
253 purple_connection_error(gc,
254 _("Resuming detached session failed. "
255 "Press Reconnect to create new connection."));
256 g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
257 break;
258
259 case SILC_CLIENT_CONN_ERROR_TIMEOUT:
260 purple_connection_error(gc, _("Connection Timeout"));
261 break;
262 }
263
264 /* Error */
265 sg->conn = NULL;
266 }
267
268 static void
269 silcpurple_stream_created(SilcSocketStreamStatus status, SilcStream stream,
270 void *context)
271 {
272 PurpleConnection *gc = context;
248 SilcPurple sg; 273 SilcPurple sg;
249 SilcClient client; 274 SilcClient client;
275 SilcClientConnectionParams params;
276 const char *dfile;
277
278 sg = gc->proto_data;
279
280 if (status != SILC_SOCKET_OK) {
281 purple_connection_error(gc, _("Connection failed"));
282 silc_pkcs_public_key_free(sg->public_key);
283 silc_pkcs_private_key_free(sg->private_key);
284 silc_free(sg);
285 gc->proto_data = NULL;
286 return;
287 }
288
289 client = sg->client;
290
291 /* Progress */
292 if (params.detach_data) {
293 purple_connection_update_progress(gc, _("Resuming session"), 2, 5);
294 sg->resuming = TRUE;
295 } else {
296 purple_connection_update_progress(gc, _("Performing key exchange"), 2, 5);
297 }
298
299 /* Get session detachment data, if available */
300 memset(&params, 0, sizeof(params));
301 dfile = silcpurple_session_file(purple_account_get_username(sg->account));
302 params.detach_data = (unsigned char *)silc_file_readfile(dfile, &params.detach_data_len);
303 if (params.detach_data)
304 params.detach_data[params.detach_data_len] = 0;
305 params.ignore_requested_attributes =
306 purple_account_get_bool(sg->account, "reject-attrs", FALSE);
307 params.pfs = purple_account_get_bool(sg->account, "pfs", FALSE);
308
309 /* Perform SILC Key Exchange. */
310 silc_client_key_exchange(sg->client, &params, sg->public_key,
311 sg->private_key, stream, SILC_CONN_SERVER,
312 silcpurple_connect_cb, gc);
313
314 silc_free(params.detach_data);
315 }
316
317 static void
318 silcpurple_login_connected(gpointer data, gint source, const gchar *error_message)
319 {
320 PurpleConnection *gc = data;
321 SilcPurple sg;
322
323 g_return_if_fail(gc != NULL);
324
325 sg = gc->proto_data;
326
327 if (source < 0) {
328 purple_connection_error(gc, _("Connection failed"));
329 silc_pkcs_public_key_free(sg->public_key);
330 silc_pkcs_private_key_free(sg->private_key);
331 silc_free(sg);
332 gc->proto_data = NULL;
333 return;
334 }
335
336 /* Wrap socket to TCP stream */
337 silc_socket_tcp_stream_create(source, TRUE, FALSE,
338 sg->client->schedule,
339 silcpurple_stream_created, gc);
340 }
341
342 static void silcpurple_running(SilcClient client, void *context)
343 {
344 PurpleAccount *account = context;
345 PurpleConnection *gc = account->gc;
346 SilcPurple sg;
347 char pkd[256], prd[256];
348
349 sg = silc_calloc(1, sizeof(*sg));
350 if (!sg)
351 return;
352 memset(sg, 0, sizeof(*sg));
353 sg->client = client;
354 sg->gc = gc;
355 sg->account = account;
356 sg->scheduler = SILC_PTR_TO_32(gc->proto_data);
357 gc->proto_data = sg;
358
359 /* Progress */
360 purple_connection_update_progress(gc, _("Connecting to SILC Server"), 1, 5);
361
362 /* Load SILC key pair */
363 g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir());
364 g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir());
365 if (!silc_load_key_pair((char *)purple_account_get_string(account, "public-key", pkd),
366 (char *)purple_account_get_string(account, "private-key", prd),
367 (gc->password == NULL) ? "" : gc->password,
368 &sg->public_key, &sg->private_key)) {
369 g_snprintf(pkd, sizeof(pkd), _("Could not load SILC key pair"));
370 purple_connection_error(gc, pkd);
371 gc->proto_data = NULL;
372 silc_free(sg);
373 return;
374 }
375
376 /* Connect to the SILC server */
377 if (purple_proxy_connect(gc, account,
378 purple_account_get_string(account, "server",
379 "silc.silcnet.org"),
380 purple_account_get_int(account, "port", 706),
381 silcpurple_login_connected, gc) == NULL)
382 {
383 purple_connection_error(gc, _("Unable to create connection"));
384 gc->proto_data = NULL;
385 silc_free(sg);
386 return;
387 }
388 }
389
390 static void
391 silcpurple_login(PurpleAccount *account)
392 {
393 SilcClient client;
394 PurpleConnection *gc;
250 SilcClientParams params; 395 SilcClientParams params;
251 PurpleConnection *gc;
252 char pkd[256], prd[256];
253 const char *cipher, *hmac; 396 const char *cipher, *hmac;
254 char *realname; 397 char *username, *hostname, *realname, **up;
398 guint scheduler;
255 int i; 399 int i;
256 400
257 gc = account->gc; 401 gc = account->gc;
258 if (!gc) 402 if (!gc)
259 return; 403 return;
260 gc->proto_data = NULL; 404 gc->proto_data = NULL;
261 405
262 memset(&params, 0, sizeof(params)); 406 memset(&params, 0, sizeof(params));
263 strcat(params.nickname_format, "%n@%h%a"); 407 strcat(params.nickname_format, "%n#a");
264 params.nickname_parse = silcpurple_nickname_parse;
265 params.ignore_requested_attributes =
266 purple_account_get_bool(account, "reject-attrs", FALSE);
267 408
268 /* Allocate SILC client */ 409 /* Allocate SILC client */
269 client = silc_client_alloc(&ops, &params, gc, NULL); 410 client = silc_client_alloc(&ops, &params, gc, NULL);
270 if (!client) { 411 if (!client) {
271 purple_connection_error(gc, _("Out of memory")); 412 purple_connection_error(gc, _("Out of memory"));
272 return; 413 return;
273 } 414 }
274 415
275 /* Get username, real name and local hostname for SILC library */ 416 /* Get username, real name and local hostname for SILC library */
276 if (purple_account_get_username(account)) { 417 if (!purple_account_get_username(account))
277 const char *u = purple_account_get_username(account); 418 purple_account_set_username(account, silc_get_username());
278 char **up = g_strsplit(u, "@", 2); 419
279 client->username = strdup(up[0]); 420 username = (char *)purple_account_get_username(account);
280 g_strfreev(up); 421 up = g_strsplit(username, "@", 2);
281 } else { 422 username = strdup(up[0]);
282 client->username = silc_get_username(); 423 g_strfreev(up);
283 purple_account_set_username(account, client->username); 424
284 } 425 if (!purple_account_get_user_info(account)) {
285 realname = silc_get_real_name(); 426 purple_account_set_user_info(account, silc_get_real_name());
286 if (purple_account_get_user_info(account)) { 427 if (!purple_account_get_user_info(account))
287 client->realname = strdup(purple_account_get_user_info(account)); 428 purple_account_set_user_info(account,
288 free(realname); 429 "John T. Noname");
289 } else if ((silc_get_real_name() != NULL) && (*realname != '\0')) { 430 }
290 client->realname = realname; 431 realname = (char *)purple_account_get_user_info(account);
291 purple_account_set_user_info(account, client->realname); 432 hostname = silc_net_localhost();
292 } else { 433
293 free(realname); 434 purple_connection_set_display_name(gc, username);
294 client->realname = strdup(_("John Noname"));
295 }
296 client->hostname = silc_net_localhost();
297
298 purple_connection_set_display_name(gc, client->username);
299 435
300 /* Register requested cipher and HMAC */ 436 /* Register requested cipher and HMAC */
301 cipher = purple_account_get_string(account, "cipher", SILC_DEFAULT_CIPHER); 437 cipher = purple_account_get_string(account, "cipher",
438 SILC_DEFAULT_CIPHER);
302 for (i = 0; silc_default_ciphers[i].name; i++) 439 for (i = 0; silc_default_ciphers[i].name; i++)
303 if (!strcmp(silc_default_ciphers[i].name, cipher)) { 440 if (!strcmp(silc_default_ciphers[i].name, cipher)) {
304 silc_cipher_register(&(silc_default_ciphers[i])); 441 silc_cipher_register(&(silc_default_ciphers[i]));
305 break; 442 break;
306 } 443 }
310 silc_hmac_register(&(silc_default_hmacs[i])); 447 silc_hmac_register(&(silc_default_hmacs[i]));
311 break; 448 break;
312 } 449 }
313 450
314 /* Init SILC client */ 451 /* Init SILC client */
315 if (!silc_client_init(client)) { 452 if (!silc_client_init(client, username, hostname, realname,
453 silcpurple_running, account)) {
316 gc->wants_to_die = TRUE; 454 gc->wants_to_die = TRUE;
317 purple_connection_error(gc, _("Cannot initialize SILC protocol")); 455 purple_connection_error(gc, _("Cannot initialize SILC protocol"));
318 return; 456 return;
319 } 457 }
320 458
321 /* Check the ~/.silc dir and create it, and new key pair if necessary. */ 459 /* Check the ~/.silc dir and create it, and new key pair if necessary. */
322 if (!silcpurple_check_silc_dir(gc)) { 460 if (!silcpurple_check_silc_dir(gc)) {
323 gc->wants_to_die = TRUE; 461 gc->wants_to_die = TRUE;
324 purple_connection_error(gc, _("Cannot find/access ~/.silc directory")); 462 purple_connection_error(gc, _("Error loading SILC key pair"));
325 return;
326 }
327
328 /* Progress */
329 purple_connection_update_progress(gc, _("Connecting to SILC Server"), 1, 5);
330
331 /* Load SILC key pair */
332 g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir());
333 g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir());
334 if (!silc_load_key_pair((char *)purple_account_get_string(account, "public-key", pkd),
335 (char *)purple_account_get_string(account, "private-key", prd),
336 (gc->password == NULL) ? "" : gc->password, &client->pkcs,
337 &client->public_key, &client->private_key)) {
338 g_snprintf(pkd, sizeof(pkd), _("Could not load SILC key pair: %s"), strerror(errno));
339 purple_connection_error(gc, pkd);
340 return;
341 }
342
343 sg = silc_calloc(1, sizeof(*sg));
344 if (!sg)
345 return;
346 memset(sg, 0, sizeof(*sg));
347 sg->client = client;
348 sg->gc = gc;
349 sg->account = account;
350 gc->proto_data = sg;
351
352 /* Connect to the SILC server */
353 if (purple_proxy_connect(gc, account,
354 purple_account_get_string(account, "server",
355 "silc.silcnet.org"),
356 purple_account_get_int(account, "port", 706),
357 silcpurple_login_connected, gc) == NULL)
358 {
359 purple_connection_error(gc, _("Unable to create connection"));
360 return; 463 return;
361 } 464 }
362 465
363 /* Schedule SILC using Glib's event loop */ 466 /* Schedule SILC using Glib's event loop */
364 sg->scheduler = purple_timeout_add(300, (GSourceFunc)silcpurple_scheduler, sg); 467 scheduler = purple_timeout_add(300, (GSourceFunc)silcpurple_scheduler, client);
468 gc->proto_data = SILC_32_TO_PTR(scheduler);
365 } 469 }
366 470
367 static int 471 static int
368 silcpurple_close_final(gpointer *context) 472 silcpurple_close_final(gpointer *context)
369 { 473 {
370 SilcPurple sg = (SilcPurple)context; 474 SilcPurple sg = (SilcPurple)context;
371 silc_client_stop(sg->client); 475 silc_client_stop(sg->client, NULL, NULL);
372 silc_client_free(sg->client); 476 silc_client_free(sg->client);
373 #ifdef HAVE_SILCMIME_H 477 #ifdef HAVE_SILCMIME_H
374 if (sg->mimeass) 478 if (sg->mimeass)
375 silc_mime_assembler_free(sg->mimeass); 479 silc_mime_assembler_free(sg->mimeass);
376 #endif 480 #endif
385 489
386 g_return_if_fail(sg != NULL); 490 g_return_if_fail(sg != NULL);
387 491
388 /* Send QUIT */ 492 /* Send QUIT */
389 silc_client_command_call(sg->client, sg->conn, NULL, 493 silc_client_command_call(sg->client, sg->conn, NULL,
390 "QUIT", "Download this: " PURPLE_WEBSITE, NULL); 494 "QUIT", "Download Pidgin: " PURPLE_WEBSITE, NULL);
391 495
392 if (sg->conn) 496 if (sg->conn)
393 silc_client_close_connection(sg->client, sg->conn); 497 silc_client_close_connection(sg->client, sg->conn);
394 498
395 purple_timeout_remove(sg->scheduler); 499 purple_timeout_remove(sg->scheduler);
593 minvincible = FALSE, minlove = FALSE, msleepy = FALSE, 697 minvincible = FALSE, minlove = FALSE, msleepy = FALSE,
594 mbored = FALSE, mexcited = FALSE, manxious = FALSE; 698 mbored = FALSE, mexcited = FALSE, manxious = FALSE;
595 gboolean cemail = FALSE, ccall = FALSE, csms = FALSE, 699 gboolean cemail = FALSE, ccall = FALSE, csms = FALSE,
596 cmms = FALSE, cchat = TRUE, cvideo = FALSE; 700 cmms = FALSE, cchat = TRUE, cvideo = FALSE;
597 gboolean device = TRUE; 701 gboolean device = TRUE;
598 char status[1024]; 702 char status[1024], tz[16];
599 703
600 sg = gc->proto_data; 704 sg = gc->proto_data;
601 if (!sg) 705 if (!sg)
602 return; 706 return;
603 707
720 g = purple_request_field_group_new(NULL); 824 g = purple_request_field_group_new(NULL);
721 f = purple_request_field_string_new("vcard", _("Your VCard File"), 825 f = purple_request_field_string_new("vcard", _("Your VCard File"),
722 purple_account_get_string(sg->account, "vcard", ""), 826 purple_account_get_string(sg->account, "vcard", ""),
723 FALSE); 827 FALSE);
724 purple_request_field_group_add_field(g, f); 828 purple_request_field_group_add_field(g, f);
725 #ifdef _WIN32 829
726 f = purple_request_field_string_new("timezone", _("Timezone"), _tzname[0], FALSE); 830 silc_timezone(tz, sizeof(tz));
727 #else 831 f = purple_request_field_string_new("timezone", _("Timezone (UTC)"), tz, FALSE);
728 f = purple_request_field_string_new("timezone", _("Timezone"), tzname[0], FALSE);
729 #endif
730 purple_request_field_group_add_field(g, f); 832 purple_request_field_group_add_field(g, f);
731 purple_request_fields_add_group(fields, g); 833 purple_request_fields_add_group(fields, g);
732 834
733 purple_request_fields(gc, _("User Online Status Attributes"), 835 purple_request_fields(gc, _("User Online Status Attributes"),
734 _("User Online Status Attributes"), 836 _("User Online Status Attributes"),
859 o = purple_request_field_string_get_value(f); 961 o = purple_request_field_string_get_value(f);
860 f = purple_request_fields_get_field(fields, "c"); 962 f = purple_request_fields_get_field(fields, "c");
861 if (f) 963 if (f)
862 c = purple_request_field_string_get_value(f); 964 c = purple_request_field_string_get_value(f);
863 965
864 identifier = silc_pkcs_encode_identifier((char *)un, (char *)hn, 966 identifier = silc_pkcs_silc_encode_identifier((char *)un, (char *)hn,
865 (char *)rn, (char *)e, (char *)o, (char *)c); 967 (char *)rn, (char *)e,
968 (char *)o, (char *)c,
969 NULL);
866 970
867 /* Create the key pair */ 971 /* Create the key pair */
868 if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS, keylen, pkfile, prfile, 972 if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS, keylen, pkfile, prfile,
869 identifier, pass1, NULL, &public_key, NULL, 973 identifier, pass1, &public_key, NULL,
870 FALSE)) { 974 FALSE)) {
871 purple_notify_error( 975 purple_notify_error(
872 gc, _("Create New SILC Key Pair"), _("Key Pair Generation failed"), NULL); 976 gc, _("Create New SILC Key Pair"), _("Key Pair Generation failed"), NULL);
873 return; 977 return;
874 } 978 }
939 purple_request_field_string_set_masked(f, TRUE); 1043 purple_request_field_string_set_masked(f, TRUE);
940 purple_request_field_group_add_field(g, f); 1044 purple_request_field_group_add_field(g, f);
941 purple_request_fields_add_group(fields, g); 1045 purple_request_fields_add_group(fields, g);
942 1046
943 purple_request_fields(gc, _("Create New SILC Key Pair"), 1047 purple_request_fields(gc, _("Create New SILC Key Pair"),
944 _("Create New SILC Key Pair"), NULL, fields, 1048 _("Create New SILC Key Pair"), NULL, fields,
945 _("Generate Key Pair"), G_CALLBACK(silcpurple_create_keypair_cb), 1049 _("Generate Key Pair"), G_CALLBACK(silcpurple_create_keypair_cb),
946 _("Cancel"), G_CALLBACK(silcpurple_create_keypair_cancel), 1050 _("Cancel"), G_CALLBACK(silcpurple_create_keypair_cancel),
947 gc->account, NULL, NULL, gc); 1051 gc->account, NULL, NULL, gc);
948 1052
949 g_strfreev(u); 1053 g_strfreev(u);
950 silc_free(hostname); 1054 silc_free(hostname);
951 } 1055 }
952 1056
961 silcpurple_change_passwd(PurpleConnection *gc, const char *old, const char *new) 1065 silcpurple_change_passwd(PurpleConnection *gc, const char *old, const char *new)
962 { 1066 {
963 char prd[256]; 1067 char prd[256];
964 g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.pub", silcpurple_silcdir()); 1068 g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.pub", silcpurple_silcdir());
965 silc_change_private_key_passphrase(purple_account_get_string(gc->account, 1069 silc_change_private_key_passphrase(purple_account_get_string(gc->account,
966 "private-key", 1070 "private-key",
967 prd), old, new); 1071 prd), old, new);
968 } 1072 }
969 1073
970 static void 1074 static void
971 silcpurple_show_set_info(PurplePluginAction *action) 1075 silcpurple_show_set_info(PurplePluginAction *action)
972 { 1076 {
1026 PurpleMessageFlags gflags; 1130 PurpleMessageFlags gflags;
1027 } *SilcPurpleIM; 1131 } *SilcPurpleIM;
1028 1132
1029 static void 1133 static void
1030 silcpurple_send_im_resolved(SilcClient client, 1134 silcpurple_send_im_resolved(SilcClient client,
1031 SilcClientConnection conn, 1135 SilcClientConnection conn,
1032 SilcClientEntry *clients, 1136 SilcStatus status,
1033 SilcUInt32 clients_count, 1137 SilcDList clients,
1034 void *context) 1138 void *context)
1035 { 1139 {
1036 PurpleConnection *gc = client->application; 1140 PurpleConnection *gc = client->application;
1037 SilcPurple sg = gc->proto_data; 1141 SilcPurple sg = gc->proto_data;
1038 SilcPurpleIM im = context; 1142 SilcPurpleIM im = context;
1039 PurpleConversation *convo; 1143 PurpleConversation *convo;
1040 char tmp[256], *nickname = NULL; 1144 char tmp[256];
1041 SilcClientEntry client_entry; 1145 SilcClientEntry client_entry;
1042 #ifdef HAVE_SILCMIME_H 1146 #ifdef HAVE_SILCMIME_H
1043 SilcDList list; 1147 SilcDList list;
1044 #endif 1148 #endif
1045 1149
1046 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, im->nick, 1150 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, im->nick,
1047 sg->account); 1151 sg->account);
1048 if (!convo) 1152 if (!convo)
1049 return; 1153 return;
1050 1154
1051 if (!clients) 1155 if (!clients)
1052 goto err; 1156 goto err;
1053 1157
1054 if (clients_count > 1) { 1158 if (silc_dlist_count(clients) > 1) {
1055 silc_parse_userfqdn(im->nick, &nickname, NULL);
1056
1057 /* Find the correct one. The im->nick might be a formatted nick 1159 /* Find the correct one. The im->nick might be a formatted nick
1058 so this will find the correct one. */ 1160 so this will find the correct one. */
1059 clients = silc_client_get_clients_local(client, conn, 1161 clients = silc_client_get_clients_local(client, conn,
1060 nickname, im->nick, 1162 im->nick, FALSE);
1061 &clients_count);
1062 if (!clients) 1163 if (!clients)
1063 goto err; 1164 goto err;
1064 client_entry = clients[0]; 1165 }
1065 silc_free(clients); 1166
1066 } else { 1167 silc_dlist_start(clients);
1067 client_entry = clients[0]; 1168 client_entry = silc_dlist_get(clients);
1068 }
1069 1169
1070 #ifdef HAVE_SILCMIME_H 1170 #ifdef HAVE_SILCMIME_H
1071 /* Check for images */ 1171 /* Check for images */
1072 if (im->gflags & PURPLE_MESSAGE_IMAGES) { 1172 if (im->gflags & PURPLE_MESSAGE_IMAGES) {
1073 list = silcpurple_image_message(im->message, (SilcUInt32 *)&im->flags); 1173 list = silcpurple_image_message(im->message,
1174 (SilcUInt32 *)(void *)&im->flags);
1074 if (list) { 1175 if (list) {
1075 /* Send one or more MIME message. If more than one, they 1176 /* Send one or more MIME message. If more than one, they
1076 are MIME fragments due to over large message */ 1177 are MIME fragments due to over large message */
1077 SilcBuffer buf; 1178 SilcBuffer buf;
1078 1179
1079 silc_dlist_start(list); 1180 silc_dlist_start(list);
1080 while ((buf = silc_dlist_get(list)) != SILC_LIST_END) 1181 while ((buf = silc_dlist_get(list)) != SILC_LIST_END)
1081 silc_client_send_private_message(client, conn, 1182 silc_client_send_private_message(client, conn,
1082 client_entry, im->flags, 1183 client_entry, im->flags, NULL,
1083 buf->data, buf->len, 1184 buf->data,
1084 TRUE); 1185 silc_buffer_len(buf));
1085 silc_mime_partial_free(list); 1186 silc_mime_partial_free(list);
1086 purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname, 1187 purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname,
1087 im->message, 0, time(NULL)); 1188 im->message, 0, time(NULL));
1088 goto out; 1189 goto out;
1089 } 1190 }
1090 } 1191 }
1091 #endif 1192 #endif
1092 1193
1093 /* Send the message */ 1194 /* Send the message */
1094 silc_client_send_private_message(client, conn, client_entry, im->flags, 1195 silc_client_send_private_message(client, conn, client_entry, im->flags,
1095 (unsigned char *)im->message, im->message_len, TRUE); 1196 NULL, (unsigned char *)im->message, im->message_len);
1096 purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname, 1197 purple_conv_im_write(PURPLE_CONV_IM(convo), conn->local_entry->nickname,
1097 im->message, 0, time(NULL)); 1198 im->message, 0, time(NULL));
1098 goto out; 1199 goto out;
1099 1200
1100 err: 1201 err:
1101 g_snprintf(tmp, sizeof(tmp), 1202 g_snprintf(tmp, sizeof(tmp),
1102 _("User <I>%s</I> is not present in the network"), im->nick); 1203 _("User <I>%s</I> is not present in the network"), im->nick);
1104 1205
1105 out: 1206 out:
1106 g_free(im->nick); 1207 g_free(im->nick);
1107 g_free(im->message); 1208 g_free(im->message);
1108 silc_free(im); 1209 silc_free(im);
1109 silc_free(nickname);
1110 } 1210 }
1111 1211
1112 static int 1212 static int
1113 silcpurple_send_im(PurpleConnection *gc, const char *who, const char *message, 1213 silcpurple_send_im(PurpleConnection *gc, const char *who, const char *message,
1114 PurpleMessageFlags flags) 1214 PurpleMessageFlags flags)
1115 { 1215 {
1116 SilcPurple sg = gc->proto_data; 1216 SilcPurple sg = gc->proto_data;
1117 SilcClient client = sg->client; 1217 SilcClient client = sg->client;
1118 SilcClientConnection conn = sg->conn; 1218 SilcClientConnection conn = sg->conn;
1119 SilcClientEntry *clients; 1219 SilcDList clients;
1120 SilcUInt32 clients_count, mflags; 1220 SilcClientEntry client_entry;
1121 char *nickname, *msg, *tmp; 1221 SilcUInt32 mflags;
1222 char *msg, *tmp;
1122 int ret = 0; 1223 int ret = 0;
1123 gboolean sign = purple_account_get_bool(sg->account, "sign-verify", FALSE); 1224 gboolean sign = purple_account_get_bool(sg->account, "sign-verify", FALSE);
1124 #ifdef HAVE_SILCMIME_H 1225 #ifdef HAVE_SILCMIME_H
1125 SilcDList list; 1226 SilcDList list;
1126 #endif 1227 #endif
1139 return 0; 1240 return 0;
1140 } 1241 }
1141 mflags |= SILC_MESSAGE_FLAG_ACTION; 1242 mflags |= SILC_MESSAGE_FLAG_ACTION;
1142 } else if (strlen(msg) > 1 && msg[0] == '/') { 1243 } else if (strlen(msg) > 1 && msg[0] == '/') {
1143 if (!silc_client_command_call(client, conn, msg + 1)) 1244 if (!silc_client_command_call(client, conn, msg + 1))
1144 purple_notify_error(gc, _("Call Command"), _("Cannot call command"), 1245 purple_notify_error(gc, _("Call Command"),
1145 _("Unknown command")); 1246 _("Cannot call command"),
1247 _("Unknown command"));
1146 g_free(tmp); 1248 g_free(tmp);
1147 return 0; 1249 return 0;
1148 } 1250 }
1149 1251
1150
1151 if (!silc_parse_userfqdn(who, &nickname, NULL)) {
1152 g_free(tmp);
1153 return 0;
1154 }
1155
1156 if (sign) 1252 if (sign)
1157 mflags |= SILC_MESSAGE_FLAG_SIGNED; 1253 mflags |= SILC_MESSAGE_FLAG_SIGNED;
1158 1254
1159 /* Find client entry */ 1255 /* Find client entry */
1160 clients = silc_client_get_clients_local(client, conn, nickname, who, 1256 clients = silc_client_get_clients_local(client, conn, who, FALSE);
1161 &clients_count);
1162 if (!clients) { 1257 if (!clients) {
1163 /* Resolve unknown user */ 1258 /* Resolve unknown user */
1164 SilcPurpleIM im = silc_calloc(1, sizeof(*im)); 1259 SilcPurpleIM im = silc_calloc(1, sizeof(*im));
1165 if (!im) { 1260 if (!im) {
1166 g_free(tmp); 1261 g_free(tmp);
1169 im->nick = g_strdup(who); 1264 im->nick = g_strdup(who);
1170 im->message = g_strdup(message); 1265 im->message = g_strdup(message);
1171 im->message_len = strlen(im->message); 1266 im->message_len = strlen(im->message);
1172 im->flags = mflags; 1267 im->flags = mflags;
1173 im->gflags = flags; 1268 im->gflags = flags;
1174 silc_client_get_clients(client, conn, nickname, NULL, 1269 silc_client_get_clients(client, conn, who, NULL,
1175 silcpurple_send_im_resolved, im); 1270 silcpurple_send_im_resolved, im);
1176 silc_free(nickname);
1177 g_free(tmp); 1271 g_free(tmp);
1178 return 0; 1272 return 0;
1179 } 1273 }
1274
1275 silc_dlist_start(clients);
1276 client_entry = silc_dlist_get(clients);
1180 1277
1181 #ifdef HAVE_SILCMIME_H 1278 #ifdef HAVE_SILCMIME_H
1182 /* Check for images */ 1279 /* Check for images */
1183 if (flags & PURPLE_MESSAGE_IMAGES) { 1280 if (flags & PURPLE_MESSAGE_IMAGES) {
1184 list = silcpurple_image_message(message, &mflags); 1281 list = silcpurple_image_message(message, &mflags);
1189 1286
1190 silc_dlist_start(list); 1287 silc_dlist_start(list);
1191 while ((buf = silc_dlist_get(list)) != SILC_LIST_END) 1288 while ((buf = silc_dlist_get(list)) != SILC_LIST_END)
1192 ret = 1289 ret =
1193 silc_client_send_private_message(client, conn, 1290 silc_client_send_private_message(client, conn,
1194 clients[0], mflags, 1291 client_entry, mflags, NULL,
1195 buf->data, buf->len, 1292 buf->data,
1196 TRUE); 1293 silc_buffer_len(buf));
1197 silc_mime_partial_free(list); 1294 silc_mime_partial_free(list);
1198 g_free(tmp); 1295 g_free(tmp);
1199 silc_free(nickname); 1296 silc_client_list_free(client, conn, clients);
1200 silc_free(clients);
1201 return ret; 1297 return ret;
1202 } 1298 }
1203 } 1299 }
1204 #endif 1300 #endif
1205 1301
1206 /* Send private message directly */ 1302 /* Send private message directly */
1207 ret = silc_client_send_private_message(client, conn, clients[0], 1303 ret = silc_client_send_private_message(client, conn, client_entry,
1208 mflags, 1304 mflags, NULL,
1209 (unsigned char *)msg, 1305 (unsigned char *)msg,
1210 strlen(msg), TRUE); 1306 strlen(msg));
1211 1307
1212 g_free(tmp); 1308 g_free(tmp);
1213 silc_free(nickname); 1309 silc_client_list_free(client, conn, clients);
1214 silc_free(clients);
1215 return ret; 1310 return ret;
1216 } 1311 }
1217 1312
1218 1313
1219 static GList *silcpurple_blist_node_menu(PurpleBlistNode *node) { 1314 static GList *silcpurple_blist_node_menu(PurpleBlistNode *node) {
1220 /* split this single menu building function back into the two 1315 /* split this single menu building function back into the two
1221 original: one for buddies and one for chats */ 1316 original: one for buddies and one for chats */
1222
1223 if(PURPLE_BLIST_NODE_IS_CHAT(node)) { 1317 if(PURPLE_BLIST_NODE_IS_CHAT(node)) {
1224 return silcpurple_chat_menu((PurpleChat *) node); 1318 return silcpurple_chat_menu((PurpleChat *) node);
1225 } else if(PURPLE_BLIST_NODE_IS_BUDDY(node)) { 1319 } else if(PURPLE_BLIST_NODE_IS_BUDDY(node)) {
1226 return silcpurple_buddy_menu((PurpleBuddy *) node); 1320 return silcpurple_buddy_menu((PurpleBuddy *) node);
1227 } else { 1321 } else {
1546 1640
1547 if (sg == NULL) 1641 if (sg == NULL)
1548 return PURPLE_CMD_RET_FAILED; 1642 return PURPLE_CMD_RET_FAILED;
1549 1643
1550 silc_client_command_call(sg->client, sg->conn, NULL, 1644 silc_client_command_call(sg->client, sg->conn, NULL,
1551 "QUIT", (args && args[0]) ? args[0] : "Download this: " PURPLE_WEBSITE, NULL); 1645 "QUIT", (args && args[0]) ? args[0] : "Download Pidgin: " PURPLE_WEBSITE, NULL);
1552 1646
1553 return PURPLE_CMD_RET_OK; 1647 return PURPLE_CMD_RET_OK;
1554 } 1648 }
1555 1649
1556 static PurpleCmdRet silcpurple_cmd_call(PurpleConversation *conv, 1650 static PurpleCmdRet silcpurple_cmd_call(PurpleConversation *conv,
1727 OPT_PROTO_PASSWORD_OPTIONAL | OPT_PROTO_IM_IMAGE, 1821 OPT_PROTO_PASSWORD_OPTIONAL | OPT_PROTO_IM_IMAGE,
1728 #else 1822 #else
1729 OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | 1823 OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME |
1730 OPT_PROTO_PASSWORD_OPTIONAL, 1824 OPT_PROTO_PASSWORD_OPTIONAL,
1731 #endif 1825 #endif
1732 NULL, /* user_splits */ 1826 NULL, /* user_splits */
1733 NULL, /* protocol_options */ 1827 NULL, /* protocol_options */
1734 #ifdef SILC_ATTRIBUTE_USER_ICON 1828 #ifdef SILC_ATTRIBUTE_USER_ICON
1735 {"jpeg,gif,png,bmp", 0, 0, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */ 1829 {"jpeg,gif,png,bmp", 0, 0, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY}, /* icon_spec */
1736 #else 1830 #else
1737 NO_BUDDY_ICONS, 1831 NO_BUDDY_ICONS,
1738 #endif 1832 #endif
1739 silcpurple_list_icon, /* list_icon */ 1833 silcpurple_list_icon, /* list_icon */
1740 NULL, /* list_emblems */ 1834 NULL, /* list_emblems */
1741 silcpurple_status_text, /* status_text */ 1835 silcpurple_status_text, /* status_text */
1742 silcpurple_tooltip_text, /* tooltip_text */ 1836 silcpurple_tooltip_text, /* tooltip_text */
1743 silcpurple_away_states, /* away_states */ 1837 silcpurple_away_states, /* away_states */
1744 silcpurple_blist_node_menu, /* blist_node_menu */ 1838 silcpurple_blist_node_menu, /* blist_node_menu */
1745 silcpurple_chat_info, /* chat_info */ 1839 silcpurple_chat_info, /* chat_info */
1746 silcpurple_chat_info_defaults,/* chat_info_defaults */ 1840 silcpurple_chat_info_defaults, /* chat_info_defaults */
1747 silcpurple_login, /* login */ 1841 silcpurple_login, /* login */
1748 silcpurple_close, /* close */ 1842 silcpurple_close, /* close */
1749 silcpurple_send_im, /* send_im */ 1843 silcpurple_send_im, /* send_im */
1750 silcpurple_set_info, /* set_info */ 1844 silcpurple_set_info, /* set_info */
1751 NULL, /* send_typing */ 1845 NULL, /* send_typing */
1752 silcpurple_get_info, /* get_info */ 1846 silcpurple_get_info, /* get_info */
1753 silcpurple_set_status, /* set_status */ 1847 silcpurple_set_status, /* set_status */
1754 silcpurple_idle_set, /* set_idle */ 1848 silcpurple_idle_set, /* set_idle */
1755 silcpurple_change_passwd, /* change_passwd */ 1849 silcpurple_change_passwd, /* change_passwd */
1756 silcpurple_add_buddy, /* add_buddy */ 1850 silcpurple_add_buddy, /* add_buddy */
1757 NULL, /* add_buddies */ 1851 NULL, /* add_buddies */
1758 silcpurple_remove_buddy, /* remove_buddy */ 1852 silcpurple_remove_buddy, /* remove_buddy */
1759 NULL, /* remove_buddies */ 1853 NULL, /* remove_buddies */
1760 NULL, /* add_permit */ 1854 NULL, /* add_permit */
1761 NULL, /* add_deny */ 1855 NULL, /* add_deny */
1762 NULL, /* rem_permit */ 1856 NULL, /* rem_permit */
1763 NULL, /* rem_deny */ 1857 NULL, /* rem_deny */
1764 NULL, /* set_permit_deny */ 1858 NULL, /* set_permit_deny */
1765 silcpurple_chat_join, /* join_chat */ 1859 silcpurple_chat_join, /* join_chat */
1766 NULL, /* reject_chat */ 1860 NULL, /* reject_chat */
1767 silcpurple_get_chat_name, /* get_chat_name */ 1861 silcpurple_get_chat_name, /* get_chat_name */
1768 silcpurple_chat_invite, /* chat_invite */ 1862 silcpurple_chat_invite, /* chat_invite */
1769 silcpurple_chat_leave, /* chat_leave */ 1863 silcpurple_chat_leave, /* chat_leave */
1770 NULL, /* chat_whisper */ 1864 NULL, /* chat_whisper */
1771 silcpurple_chat_send, /* chat_send */ 1865 silcpurple_chat_send, /* chat_send */
1772 silcpurple_keepalive, /* keepalive */ 1866 silcpurple_keepalive, /* keepalive */
1773 NULL, /* register_user */ 1867 NULL, /* register_user */
1774 NULL, /* get_cb_info */ 1868 NULL, /* get_cb_info */
1775 NULL, /* get_cb_away */ 1869 NULL, /* get_cb_away */
1776 NULL, /* alias_buddy */ 1870 NULL, /* alias_buddy */
1777 NULL, /* group_buddy */ 1871 NULL, /* group_buddy */
1778 NULL, /* rename_group */ 1872 NULL, /* rename_group */
1779 NULL, /* buddy_free */ 1873 NULL, /* buddy_free */
1780 NULL, /* convo_closed */ 1874 NULL, /* convo_closed */
1781 NULL, /* normalize */ 1875 NULL, /* normalize */
1782 #ifdef SILC_ATTRIBUTE_USER_ICON 1876 #ifdef SILC_ATTRIBUTE_USER_ICON
1783 silcpurple_buddy_set_icon, /* set_buddy_icon */ 1877 silcpurple_buddy_set_icon, /* set_buddy_icon */
1784 #else 1878 #else
1785 NULL, 1879 NULL,
1786 #endif 1880 #endif
1787 NULL, /* remove_group */ 1881 NULL, /* remove_group */
1788 NULL, /* get_cb_real_name */ 1882 NULL, /* get_cb_real_name */
1789 silcpurple_chat_set_topic, /* set_chat_topic */ 1883 silcpurple_chat_set_topic, /* set_chat_topic */
1790 NULL, /* find_blist_chat */ 1884 NULL, /* find_blist_chat */
1791 silcpurple_roomlist_get_list, /* roomlist_get_list */ 1885 silcpurple_roomlist_get_list, /* roomlist_get_list */
1792 silcpurple_roomlist_cancel, /* roomlist_cancel */ 1886 silcpurple_roomlist_cancel, /* roomlist_cancel */
1793 NULL, /* roomlist_expand_category */ 1887 NULL, /* roomlist_expand_category */
1794 NULL, /* can_receive_file */ 1888 NULL, /* can_receive_file */
1795 silcpurple_ftp_send_file, /* send_file */ 1889 silcpurple_ftp_send_file, /* send_file */
1796 silcpurple_ftp_new_xfer, /* new_xfer */ 1890 silcpurple_ftp_new_xfer, /* new_xfer */
1797 NULL, /* offline_message */ 1891 NULL, /* offline_message */
1798 &silcpurple_wb_ops, /* whiteboard_prpl_ops */ 1892 &silcpurple_wb_ops, /* whiteboard_prpl_ops */
1799 NULL, /* send_raw */ 1893 NULL, /* send_raw */
1800 NULL, /* roomlist_room_serialize */ 1894 NULL, /* roomlist_room_serialize */
1801 1895
1802 /* padding */ 1896 /* padding */
1803 NULL, 1897 NULL,
1804 NULL, 1898 NULL,
1805 NULL, 1899 NULL,
1809 static PurplePluginInfo info = 1903 static PurplePluginInfo info =
1810 { 1904 {
1811 PURPLE_PLUGIN_MAGIC, 1905 PURPLE_PLUGIN_MAGIC,
1812 PURPLE_MAJOR_VERSION, 1906 PURPLE_MAJOR_VERSION,
1813 PURPLE_MINOR_VERSION, 1907 PURPLE_MINOR_VERSION,
1814 PURPLE_PLUGIN_PROTOCOL, /**< type */ 1908 PURPLE_PLUGIN_PROTOCOL, /**< type */
1815 NULL, /**< ui_requirement */ 1909 NULL, /**< ui_requirement */
1816 0, /**< flags */ 1910 0, /**< flags */
1817 NULL, /**< dependencies */ 1911 NULL, /**< dependencies */
1818 PURPLE_PRIORITY_DEFAULT, /**< priority */ 1912 PURPLE_PRIORITY_DEFAULT, /**< priority */
1819 1913
1820 "prpl-silc", /**< id */ 1914 "prpl-silc", /**< id */
1821 "SILC", /**< name */ 1915 "SILC", /**< name */
1822 "1.0", /**< version */ 1916 "1.1", /**< version */
1823 /** summary */ 1917 /** summary */
1824 N_("SILC Protocol Plugin"), 1918 N_("SILC Protocol Plugin"),
1825 /** description */ 1919 /** description */
1826 N_("Secure Internet Live Conferencing (SILC) Protocol"), 1920 N_("Secure Internet Live Conferencing (SILC) Protocol"),
1827 "Pekka Riikonen", /**< author */ 1921 "Pekka Riikonen", /**< author */
1828 "http://silcnet.org/", /**< homepage */ 1922 "http://silcnet.org/", /**< homepage */
1829 1923
1830 NULL, /**< load */ 1924 NULL, /**< load */
1831 NULL, /**< unload */ 1925 NULL, /**< unload */
1832 NULL, /**< destroy */ 1926 NULL, /**< destroy */
1833 1927
1834 NULL, /**< ui_info */ 1928 NULL, /**< ui_info */
1835 &prpl_info, /**< extra_info */ 1929 &prpl_info, /**< extra_info */
1836 NULL, /**< prefs_info */ 1930 NULL, /**< prefs_info */
1837 silcpurple_actions, 1931 silcpurple_actions,
1838 1932
1839 /* padding */ 1933 /* padding */
1840 NULL, 1934 NULL,
1841 NULL, 1935 NULL,
1858 split = purple_account_user_split_new(_("Network"), "silcnet.org", '@'); 1952 split = purple_account_user_split_new(_("Network"), "silcnet.org", '@');
1859 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); 1953 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
1860 1954
1861 /* Account options */ 1955 /* Account options */
1862 option = purple_account_option_string_new(_("Connect server"), 1956 option = purple_account_option_string_new(_("Connect server"),
1863 "server", 1957 "server",
1864 "silc.silcnet.org"); 1958 "silc.silcnet.org");
1865 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 1959 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1866 option = purple_account_option_int_new(_("Port"), "port", 706); 1960 option = purple_account_option_int_new(_("Port"), "port", 706);
1867 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 1961 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1868 g_snprintf(tmp, sizeof(tmp), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir()); 1962 g_snprintf(tmp, sizeof(tmp), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir());
1869 option = purple_account_option_string_new(_("Public Key file"), 1963 option = purple_account_option_string_new(_("Public Key file"),
1870 "public-key", tmp); 1964 "public-key", tmp);
1871 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 1965 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1872 g_snprintf(tmp, sizeof(tmp), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir()); 1966 g_snprintf(tmp, sizeof(tmp), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir());
1873 option = purple_account_option_string_new(_("Private Key file"), 1967 option = purple_account_option_string_new(_("Private Key file"),
1874 "private-key", tmp); 1968 "private-key", tmp);
1875 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 1969 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1876 1970
1877 for (i = 0; silc_default_ciphers[i].name; i++) { 1971 for (i = 0; silc_default_ciphers[i].name; i++) {
1878 kvp = g_new0(PurpleKeyValuePair, 1); 1972 kvp = g_new0(PurpleKeyValuePair, 1);
1879 kvp->key = g_strdup(silc_default_ciphers[i].name); 1973 kvp->key = g_strdup(silc_default_ciphers[i].name);
1891 list = g_list_append(list, kvp); 1985 list = g_list_append(list, kvp);
1892 } 1986 }
1893 option = purple_account_option_list_new(_("HMAC"), "hmac", list); 1987 option = purple_account_option_list_new(_("HMAC"), "hmac", list);
1894 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 1988 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1895 1989
1990 option = purple_account_option_bool_new(_("Use Perfect Forward Secrecy"),
1991 "pfs", FALSE);
1992 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1993
1896 option = purple_account_option_bool_new(_("Public key authentication"), 1994 option = purple_account_option_bool_new(_("Public key authentication"),
1897 "pubkey-auth", FALSE); 1995 "pubkey-auth", FALSE);
1898 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 1996 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1899 option = purple_account_option_bool_new(_("Reject watching by other users"), 1997 option = purple_account_option_bool_new(_("Reject watching by other users"),
1900 "reject-watch", FALSE); 1998 "reject-watch", FALSE);
1901 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 1999 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1902 option = purple_account_option_bool_new(_("Block invites"), 2000 option = purple_account_option_bool_new(_("Block invites"),
1903 "block-invites", FALSE); 2001 "block-invites", FALSE);
1904 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 2002 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1905 option = purple_account_option_bool_new(_("Block IMs without Key Exchange"), 2003 option = purple_account_option_bool_new(_("Block IMs without Key Exchange"),
1906 "block-ims", FALSE); 2004 "block-ims", FALSE);
1907 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 2005 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1908 option = purple_account_option_bool_new(_("Reject online status attribute requests"), 2006 option = purple_account_option_bool_new(_("Reject online status attribute requests"),
1909 "reject-attrs", FALSE); 2007 "reject-attrs", FALSE);
1910 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 2008 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1911 option = purple_account_option_bool_new(_("Block messages to whiteboard"), 2009 option = purple_account_option_bool_new(_("Block messages to whiteboard"),
1912 "block-wb", FALSE); 2010 "block-wb", FALSE);
1913 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 2011 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1914 option = purple_account_option_bool_new(_("Automatically open whiteboard"), 2012 option = purple_account_option_bool_new(_("Automatically open whiteboard"),
1915 "open-wb", FALSE); 2013 "open-wb", FALSE);
1916 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 2014 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1917 option = purple_account_option_bool_new(_("Digitally sign and verify all messages"), 2015 option = purple_account_option_bool_new(_("Digitally sign and verify all messages"),
1918 "sign-verify", FALSE); 2016 "sign-verify", FALSE);
1919 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 2017 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1920 2018
1921 purple_prefs_remove("/plugins/prpl/silc"); 2019 purple_prefs_remove("/plugins/prpl/silc");
1922 2020
2021 silc_log_set_callback(SILC_LOG_ERROR, silcpurple_log_error, NULL);
1923 silcpurple_register_commands(); 2022 silcpurple_register_commands();
2023
2024 #if 0
2025 silc_log_debug(TRUE);
2026 silc_log_set_debug_string("*client*");
2027 #endif
1924 2028
1925 #ifdef _WIN32 2029 #ifdef _WIN32
1926 silc_net_win32_init(); 2030 silc_net_win32_init();
1927 #endif 2031 #endif
1928 } 2032 }