8849
|
1 /*
|
|
2
|
|
3 silcgaim_ops.c
|
|
4
|
|
5 Author: Pekka Riikonen <priikone@silcnet.org>
|
|
6
|
|
7 Copyright (C) 2004 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 "silcincludes.h"
|
|
21 #include "silcclient.h"
|
|
22 #include "silcgaim.h"
|
|
23
|
|
24 /* Message sent to the application by library. `conn' associates the
|
|
25 message to a specific connection. `conn', however, may be NULL.
|
|
26 The `type' indicates the type of the message sent by the library.
|
|
27 The application can for example filter the message according the
|
|
28 type. */
|
|
29
|
|
30 static void
|
|
31 silc_say(SilcClient client, SilcClientConnection conn,
|
|
32 SilcClientMessageType type, char *msg, ...)
|
|
33 {
|
|
34 /* Nothing */
|
|
35 }
|
|
36
|
|
37
|
|
38 /* Message for a channel. The `sender' is the sender of the message
|
|
39 The `channel' is the channel. The `message' is the message. Note
|
|
40 that `message' maybe NULL. The `flags' indicates message flags
|
|
41 and it is used to determine how the message can be interpreted
|
|
42 (like it may tell the message is multimedia message). */
|
|
43
|
|
44 static void
|
|
45 silc_channel_message(SilcClient client, SilcClientConnection conn,
|
|
46 SilcClientEntry sender, SilcChannelEntry channel,
|
|
47 SilcMessagePayload payload, SilcChannelPrivateKey key,
|
|
48 SilcMessageFlags flags, const unsigned char *message,
|
|
49 SilcUInt32 message_len)
|
|
50 {
|
|
51 GaimConnection *gc = client->application;
|
|
52 SilcGaim sg = gc->proto_data;
|
|
53 GaimConversation *convo = NULL;
|
9359
|
54 char *msg, *tmp;
|
8849
|
55
|
|
56 if (!message)
|
|
57 return;
|
|
58
|
|
59 if (key) {
|
|
60 GList *l;
|
|
61 SilcGaimPrvgrp prv;
|
|
62
|
|
63 for (l = sg->grps; l; l = l->next)
|
|
64 if (((SilcGaimPrvgrp)l->data)->key == key) {
|
|
65 prv = l->data;
|
10246
|
66 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
67 prv->channel, sg->account);
|
8849
|
68 break;
|
|
69 }
|
|
70 }
|
|
71 if (!convo)
|
10246
|
72 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
73 channel->channel_name, sg->account);
|
8849
|
74 if (!convo)
|
|
75 return;
|
|
76
|
|
77 if (flags & SILC_MESSAGE_FLAG_SIGNED &&
|
|
78 gaim_prefs_get_bool("/plugins/prpl/silc/verify_chat")) {
|
|
79 /* XXX */
|
|
80 }
|
|
81
|
|
82 if (flags & SILC_MESSAGE_FLAG_DATA) {
|
|
83 /* XXX */
|
|
84 return;
|
|
85 }
|
|
86
|
|
87 if (flags & SILC_MESSAGE_FLAG_ACTION) {
|
9353
|
88 msg = g_strdup_printf("/me %s",
|
8849
|
89 (const char *)message);
|
|
90 if (!msg)
|
|
91 return;
|
|
92
|
9359
|
93 tmp = gaim_escape_html(msg);
|
8849
|
94 /* Send to Gaim */
|
9353
|
95 serv_got_chat_in(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(convo)),
|
|
96 sender->nickname ?
|
|
97 sender->nickname : "<unknown>", 0,
|
9359
|
98 tmp, time(NULL));
|
|
99 g_free(tmp);
|
8849
|
100 g_free(msg);
|
|
101 return;
|
|
102 }
|
|
103
|
|
104 if (flags & SILC_MESSAGE_FLAG_NOTICE) {
|
|
105 msg = g_strdup_printf("(notice) <I>%s</I> %s",
|
|
106 sender->nickname ?
|
|
107 sender->nickname : "<unknown>",
|
|
108 (const char *)message);
|
|
109 if (!msg)
|
|
110 return;
|
|
111
|
|
112 /* Send to Gaim */
|
|
113 gaim_conversation_write(convo, NULL, (const char *)msg,
|
|
114 GAIM_MESSAGE_SYSTEM, time(NULL));
|
|
115 g_free(msg);
|
|
116 return;
|
|
117 }
|
|
118
|
9359
|
119 if (flags & SILC_MESSAGE_FLAG_UTF8) {
|
|
120 tmp = gaim_escape_html((const char *)message);
|
8849
|
121 /* Send to Gaim */
|
|
122 serv_got_chat_in(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(convo)),
|
|
123 sender->nickname ?
|
|
124 sender->nickname : "<unknown>", 0,
|
9359
|
125 tmp, time(NULL));
|
|
126 g_free(tmp);
|
|
127 }
|
8849
|
128 }
|
|
129
|
|
130
|
|
131 /* Private message to the client. The `sender' is the sender of the
|
|
132 message. The message is `message'and maybe NULL. The `flags'
|
|
133 indicates message flags and it is used to determine how the message
|
|
134 can be interpreted (like it may tell the message is multimedia
|
|
135 message). */
|
|
136
|
|
137 static void
|
|
138 silc_private_message(SilcClient client, SilcClientConnection conn,
|
|
139 SilcClientEntry sender, SilcMessagePayload payload,
|
|
140 SilcMessageFlags flags, const unsigned char *message,
|
|
141 SilcUInt32 message_len)
|
|
142 {
|
|
143 GaimConnection *gc = client->application;
|
|
144 SilcGaim sg = gc->proto_data;
|
|
145 GaimConversation *convo = NULL;
|
9359
|
146 char *msg, *tmp;
|
8849
|
147
|
|
148 if (!message)
|
|
149 return;
|
|
150
|
|
151 if (sender->nickname)
|
10246
|
152 /* XXX - Should this be GAIM_CONV_IM? */
|
|
153 convo = gaim_find_conversation_with_account(GAIM_CONV_ANY,
|
|
154 sender->nickname, sg->account);
|
8849
|
155
|
|
156 if (flags & SILC_MESSAGE_FLAG_SIGNED &&
|
|
157 gaim_prefs_get_bool("/plugins/prpl/silc/verify_im")) {
|
|
158 /* XXX */
|
|
159 }
|
|
160
|
|
161 if (flags & SILC_MESSAGE_FLAG_DATA) {
|
|
162 /* XXX */
|
|
163 return;
|
|
164 }
|
|
165
|
|
166 if (flags & SILC_MESSAGE_FLAG_ACTION && convo) {
|
9353
|
167 msg = g_strdup_printf("/me %s",
|
8849
|
168 (const char *)message);
|
|
169 if (!msg)
|
|
170 return;
|
|
171
|
9359
|
172 tmp = gaim_escape_html(msg);
|
8849
|
173 /* Send to Gaim */
|
9353
|
174 serv_got_im(gc, sender->nickname ?
|
|
175 sender->nickname : "<unknown>",
|
9359
|
176 tmp, 0, time(NULL));
|
8849
|
177 g_free(msg);
|
9359
|
178 g_free(tmp);
|
8849
|
179 return;
|
|
180 }
|
|
181
|
|
182 if (flags & SILC_MESSAGE_FLAG_NOTICE && convo) {
|
|
183 msg = g_strdup_printf("(notice) <I>%s</I> %s",
|
|
184 sender->nickname ?
|
|
185 sender->nickname : "<unknown>",
|
|
186 (const char *)message);
|
|
187 if (!msg)
|
|
188 return;
|
|
189
|
|
190 /* Send to Gaim */
|
|
191 gaim_conversation_write(convo, NULL, (const char *)msg,
|
|
192 GAIM_MESSAGE_SYSTEM, time(NULL));
|
|
193 g_free(msg);
|
|
194 return;
|
|
195 }
|
|
196
|
9359
|
197 if (flags & SILC_MESSAGE_FLAG_UTF8) {
|
|
198 tmp = gaim_escape_html((const char *)message);
|
8849
|
199 /* Send to Gaim */
|
|
200 serv_got_im(gc, sender->nickname ?
|
|
201 sender->nickname : "<unknown>",
|
9359
|
202 tmp, 0, time(NULL));
|
|
203 g_free(tmp);
|
|
204 }
|
8849
|
205 }
|
|
206
|
|
207
|
|
208 /* Notify message to the client. The notify arguments are sent in the
|
|
209 same order as servers sends them. The arguments are same as received
|
|
210 from the server except for ID's. If ID is received application receives
|
|
211 the corresponding entry to the ID. For example, if Client ID is received
|
|
212 application receives SilcClientEntry. Also, if the notify type is
|
|
213 for channel the channel entry is sent to application (even if server
|
|
214 does not send it because client library gets the channel entry from
|
|
215 the Channel ID in the packet's header). */
|
|
216
|
|
217 static void
|
|
218 silc_notify(SilcClient client, SilcClientConnection conn,
|
|
219 SilcNotifyType type, ...)
|
|
220 {
|
|
221 va_list va;
|
|
222 GaimConnection *gc = client->application;
|
|
223 SilcGaim sg = gc->proto_data;
|
|
224 GaimConversation *convo;
|
|
225 SilcClientEntry client_entry, client_entry2;
|
|
226 SilcChannelEntry channel;
|
|
227 SilcServerEntry server_entry;
|
|
228 SilcIdType idtype;
|
|
229 void *entry;
|
|
230 SilcUInt32 mode;
|
|
231 SilcHashTableList htl;
|
|
232 SilcChannelUser chu;
|
|
233 char buf[512], buf2[512], *tmp, *name;
|
|
234 SilcBuffer buffer;
|
|
235 SilcNotifyType notify;
|
|
236 GaimBuddy *b;
|
|
237 int i;
|
|
238
|
|
239 va_start(va, type);
|
|
240 memset(buf, 0, sizeof(buf));
|
|
241
|
|
242 switch (type) {
|
|
243
|
|
244 case SILC_NOTIFY_TYPE_NONE:
|
|
245 break;
|
|
246
|
|
247 case SILC_NOTIFY_TYPE_INVITE:
|
|
248 {
|
|
249 GHashTable *components;
|
|
250 channel = va_arg(va, SilcChannelEntry);
|
|
251 name = va_arg(va, char *);
|
|
252 client_entry = va_arg(va, SilcClientEntry);
|
|
253
|
|
254 components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
9353
|
255 g_hash_table_insert(components, strdup("channel"), strdup(name));
|
|
256 serv_got_chat_invite(gc, name, client_entry->nickname, NULL, components);
|
8849
|
257 }
|
|
258 break;
|
|
259
|
|
260 case SILC_NOTIFY_TYPE_JOIN:
|
|
261 client_entry = va_arg(va, SilcClientEntry);
|
|
262 channel = va_arg(va, SilcChannelEntry);
|
|
263
|
|
264 /* If we joined channel, do nothing */
|
|
265 if (client_entry == conn->local_entry)
|
|
266 break;
|
|
267
|
10246
|
268 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
269 channel->channel_name, sg->account);
|
8849
|
270 if (!convo)
|
|
271 break;
|
|
272
|
|
273 /* Join user to channel */
|
8891
|
274 g_snprintf(buf, sizeof(buf), "%s@%s",
|
8849
|
275 client_entry->username, client_entry->hostname);
|
|
276 gaim_conv_chat_add_user(GAIM_CONV_CHAT(convo),
|
9846
|
277 g_strdup(client_entry->nickname), buf, GAIM_CBFLAGS_NONE, TRUE);
|
8849
|
278
|
|
279 break;
|
|
280
|
|
281 case SILC_NOTIFY_TYPE_LEAVE:
|
|
282 client_entry = va_arg(va, SilcClientEntry);
|
|
283 channel = va_arg(va, SilcChannelEntry);
|
|
284
|
10246
|
285 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
286 channel->channel_name, sg->account);
|
8849
|
287 if (!convo)
|
|
288 break;
|
|
289
|
|
290 /* Remove user from channel */
|
|
291 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(convo),
|
|
292 client_entry->nickname, NULL);
|
|
293
|
|
294 break;
|
|
295
|
|
296 case SILC_NOTIFY_TYPE_SIGNOFF:
|
|
297 client_entry = va_arg(va, SilcClientEntry);
|
|
298 tmp = va_arg(va, char *);
|
|
299
|
|
300 if (!client_entry->nickname)
|
|
301 break;
|
|
302
|
|
303 /* Remove from all channels */
|
|
304 silc_hash_table_list(client_entry->channels, &htl);
|
|
305 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
|
10246
|
306 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
307 chu->channel->channel_name, sg->account);
|
8849
|
308 if (!convo)
|
|
309 continue;
|
|
310 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(convo),
|
|
311 client_entry->nickname,
|
|
312 tmp);
|
|
313 }
|
|
314 silc_hash_table_list_reset(&htl);
|
|
315
|
|
316 break;
|
|
317
|
|
318 case SILC_NOTIFY_TYPE_TOPIC_SET:
|
9762
|
319 {
|
|
320 char *esc, *tmp2;
|
|
321 idtype = va_arg(va, int);
|
|
322 entry = va_arg(va, void *);
|
|
323 tmp = va_arg(va, char *);
|
|
324 channel = va_arg(va, SilcChannelEntry);
|
|
325
|
10246
|
326 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
327 channel->channel_name, sg->account);
|
9762
|
328 if (!convo)
|
|
329 break;
|
|
330
|
|
331 if (!tmp)
|
|
332 break;
|
|
333
|
|
334 esc = gaim_escape_html(tmp);
|
|
335 tmp2 = gaim_markup_linkify(esc);
|
|
336 g_free(esc);
|
8849
|
337
|
9762
|
338 if (idtype == SILC_ID_CLIENT) {
|
|
339 client_entry = (SilcClientEntry)entry;
|
|
340 g_snprintf(buf, sizeof(buf),
|
|
341 _("%s has changed the topic of <I>%s</I> to: %s"),
|
|
342 client_entry->nickname, channel->channel_name, tmp2);
|
|
343 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), client_entry->nickname,
|
|
344 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
|
|
345 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(convo),
|
|
346 client_entry->nickname, tmp);
|
|
347 } else if (idtype == SILC_ID_SERVER) {
|
|
348 server_entry = (SilcServerEntry)entry;
|
|
349 g_snprintf(buf, sizeof(buf),
|
|
350 _("%s has changed the topic of <I>%s</I> to: %s"),
|
|
351 server_entry->server_name, channel->channel_name, tmp2);
|
|
352 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), server_entry->server_name,
|
|
353 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
|
|
354 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(convo),
|
|
355 server_entry->server_name, tmp);
|
|
356 } else if (idtype == SILC_ID_CHANNEL) {
|
|
357 channel = (SilcChannelEntry)entry;
|
|
358 g_snprintf(buf, sizeof(buf),
|
|
359 _("%s has changed the topic of <I>%s</I> to: %s"),
|
|
360 channel->channel_name, channel->channel_name, tmp2);
|
|
361 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), channel->channel_name,
|
|
362 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
|
|
363 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(convo),
|
|
364 channel->channel_name, tmp);
|
|
365 } else {
|
|
366 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(convo), NULL, tmp);
|
|
367 }
|
8849
|
368
|
9762
|
369 g_free(tmp2);
|
|
370
|
8849
|
371 break;
|
|
372
|
|
373 }
|
|
374 case SILC_NOTIFY_TYPE_NICK_CHANGE:
|
|
375 client_entry = va_arg(va, SilcClientEntry);
|
|
376 client_entry2 = va_arg(va, SilcClientEntry);
|
|
377
|
|
378 if (!strcmp(client_entry->nickname, client_entry2->nickname))
|
|
379 break;
|
|
380
|
|
381 /* Change nick on all channels */
|
|
382 silc_hash_table_list(client_entry2->channels, &htl);
|
|
383 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
|
10246
|
384 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
385 chu->channel->channel_name, sg->account);
|
8849
|
386 if (!convo)
|
|
387 continue;
|
9628
|
388 if (gaim_conv_chat_find_user(GAIM_CONV_CHAT(convo), client_entry->nickname))
|
|
389 gaim_conv_chat_rename_user(GAIM_CONV_CHAT(convo),
|
|
390 client_entry->nickname,
|
|
391 client_entry2->nickname);
|
8849
|
392 }
|
|
393 silc_hash_table_list_reset(&htl);
|
|
394
|
|
395 break;
|
|
396
|
|
397 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
|
|
398 idtype = va_arg(va, int);
|
|
399 entry = va_arg(va, void *);
|
|
400 mode = va_arg(va, SilcUInt32);
|
|
401 (void)va_arg(va, char *);
|
|
402 (void)va_arg(va, char *);
|
|
403 (void)va_arg(va, char *);
|
|
404 (void)va_arg(va, SilcPublicKey);
|
|
405 buffer = va_arg(va, SilcBuffer);
|
|
406 channel = va_arg(va, SilcChannelEntry);
|
|
407
|
10246
|
408 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
409 channel->channel_name, sg->account);
|
8849
|
410 if (!convo)
|
|
411 break;
|
|
412
|
|
413 if (idtype == SILC_ID_CLIENT)
|
|
414 name = ((SilcClientEntry)entry)->nickname;
|
|
415 else if (idtype == SILC_ID_SERVER)
|
|
416 name = ((SilcServerEntry)entry)->server_name;
|
|
417 else
|
|
418 name = ((SilcChannelEntry)entry)->channel_name;
|
|
419 if (!name)
|
|
420 break;
|
|
421
|
|
422 if (mode) {
|
|
423 silcgaim_get_chmode_string(mode, buf2, sizeof(buf2));
|
|
424 g_snprintf(buf, sizeof(buf),
|
|
425 _("<I>%s</I> set channel <I>%s</I> modes to: %s"), name,
|
|
426 channel->channel_name, buf2);
|
|
427 } else {
|
|
428 g_snprintf(buf, sizeof(buf),
|
|
429 _("<I>%s</I> removed all channel <I>%s</I> modes"), name,
|
|
430 channel->channel_name);
|
|
431 }
|
|
432 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), channel->channel_name,
|
|
433 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
|
|
434 break;
|
|
435
|
|
436 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
|
9554
|
437 {
|
|
438 GaimConvChatBuddyFlags flags = GAIM_CBFLAGS_NONE;
|
|
439 idtype = va_arg(va, int);
|
|
440 entry = va_arg(va, void *);
|
|
441 mode = va_arg(va, SilcUInt32);
|
|
442 client_entry2 = va_arg(va, SilcClientEntry);
|
|
443 channel = va_arg(va, SilcChannelEntry);
|
8849
|
444
|
10246
|
445 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
446 channel->channel_name, sg->account);
|
9554
|
447 if (!convo)
|
|
448 break;
|
8849
|
449
|
9554
|
450 if (idtype == SILC_ID_CLIENT)
|
|
451 name = ((SilcClientEntry)entry)->nickname;
|
|
452 else if (idtype == SILC_ID_SERVER)
|
|
453 name = ((SilcServerEntry)entry)->server_name;
|
|
454 else
|
|
455 name = ((SilcChannelEntry)entry)->channel_name;
|
|
456 if (!name)
|
|
457 break;
|
8849
|
458
|
9554
|
459 if (mode) {
|
|
460 silcgaim_get_chumode_string(mode, buf2, sizeof(buf2));
|
|
461 g_snprintf(buf, sizeof(buf),
|
|
462 _("<I>%s</I> set <I>%s's</I> modes to: %s"), name,
|
|
463 client_entry2->nickname, buf2);
|
|
464 if (mode & SILC_CHANNEL_UMODE_CHANFO)
|
|
465 flags |= GAIM_CBFLAGS_FOUNDER;
|
|
466 if (mode & SILC_CHANNEL_UMODE_CHANOP)
|
|
467 flags |= GAIM_CBFLAGS_OP;
|
|
468 } else {
|
|
469 g_snprintf(buf, sizeof(buf),
|
|
470 _("<I>%s</I> removed all <I>%s's</I> modes"), name,
|
|
471 client_entry2->nickname);
|
|
472 }
|
|
473 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), channel->channel_name,
|
|
474 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
|
|
475 gaim_conv_chat_user_set_flags(GAIM_CONV_CHAT(convo), client_entry2->nickname, flags);
|
|
476 break;
|
8849
|
477 }
|
|
478
|
|
479 case SILC_NOTIFY_TYPE_MOTD:
|
|
480 tmp = va_arg(va, char *);
|
|
481 silc_free(sg->motd);
|
|
482 sg->motd = silc_memdup(tmp, strlen(tmp));
|
|
483 break;
|
|
484
|
|
485 case SILC_NOTIFY_TYPE_KICKED:
|
|
486 client_entry = va_arg(va, SilcClientEntry);
|
|
487 tmp = va_arg(va, char *);
|
|
488 client_entry2 = va_arg(va, SilcClientEntry);
|
|
489 channel = va_arg(va, SilcChannelEntry);
|
|
490
|
10246
|
491 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
492 channel->channel_name, sg->account);
|
8849
|
493 if (!convo)
|
|
494 break;
|
|
495
|
|
496 if (client_entry == conn->local_entry) {
|
|
497 /* Remove us from channel */
|
|
498 g_snprintf(buf, sizeof(buf),
|
|
499 _("You have been kicked off <I>%s</I> by <I>%s</I> (%s)"),
|
|
500 channel->channel_name, client_entry2->nickname,
|
|
501 tmp ? tmp : "");
|
|
502 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), client_entry->nickname,
|
|
503 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
|
|
504 serv_got_chat_left(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(convo)));
|
|
505 } else {
|
|
506 /* Remove user from channel */
|
|
507 g_snprintf(buf, sizeof(buf), ("Kicked by %s (%s)"),
|
|
508 client_entry2->nickname, tmp ? tmp : "");
|
9353
|
509 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(convo),
|
8849
|
510 client_entry->nickname,
|
|
511 buf);
|
|
512 }
|
|
513
|
|
514 break;
|
|
515
|
|
516 case SILC_NOTIFY_TYPE_KILLED:
|
|
517 client_entry = va_arg(va, SilcClientEntry);
|
|
518 tmp = va_arg(va, char *);
|
|
519 idtype = va_arg(va, int);
|
|
520 entry = va_arg(va, SilcClientEntry);
|
|
521
|
|
522 if (!client_entry->nickname)
|
|
523 break;
|
|
524
|
|
525 if (client_entry == conn->local_entry) {
|
|
526 if (idtype == SILC_ID_CLIENT) {
|
|
527 client_entry2 = (SilcClientEntry)entry;
|
|
528 g_snprintf(buf, sizeof(buf),
|
|
529 _("You have been killed by %s (%s)"),
|
|
530 client_entry2->nickname, tmp ? tmp : "");
|
|
531 } else if (idtype == SILC_ID_SERVER) {
|
|
532 server_entry = (SilcServerEntry)entry;
|
|
533 g_snprintf(buf, sizeof(buf),
|
|
534 _("You have been killed by %s (%s)"),
|
|
535 server_entry->server_name, tmp ? tmp : "");
|
|
536 } else if (idtype == SILC_ID_CHANNEL) {
|
|
537 channel = (SilcChannelEntry)entry;
|
|
538 g_snprintf(buf, sizeof(buf),
|
|
539 _("You have been killed by %s (%s)"),
|
|
540 channel->channel_name, tmp ? tmp : "");
|
|
541 }
|
|
542
|
|
543 /* Remove us from all channels */
|
|
544 silc_hash_table_list(client_entry->channels, &htl);
|
|
545 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
|
10246
|
546 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
547 chu->channel->channel_name, sg->account);
|
8849
|
548 if (!convo)
|
|
549 continue;
|
|
550 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), client_entry->nickname,
|
|
551 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
|
|
552 serv_got_chat_left(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(convo)));
|
|
553 }
|
|
554 silc_hash_table_list_reset(&htl);
|
|
555
|
|
556 } else {
|
|
557 if (idtype == SILC_ID_CLIENT) {
|
|
558 client_entry2 = (SilcClientEntry)entry;
|
|
559 g_snprintf(buf, sizeof(buf),
|
|
560 _("Killed by %s (%s)"),
|
|
561 client_entry2->nickname, tmp ? tmp : "");
|
|
562 } else if (idtype == SILC_ID_SERVER) {
|
|
563 server_entry = (SilcServerEntry)entry;
|
|
564 g_snprintf(buf, sizeof(buf),
|
|
565 _("Killed by %s (%s)"),
|
|
566 server_entry->server_name, tmp ? tmp : "");
|
|
567 } else if (idtype == SILC_ID_CHANNEL) {
|
|
568 channel = (SilcChannelEntry)entry;
|
|
569 g_snprintf(buf, sizeof(buf),
|
|
570 _("Killed by %s (%s)"),
|
|
571 channel->channel_name, tmp ? tmp : "");
|
|
572 }
|
|
573
|
|
574 /* Remove user from all channels */
|
|
575 silc_hash_table_list(client_entry->channels, &htl);
|
|
576 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
|
10246
|
577 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
578 chu->channel->channel_name, sg->account);
|
8849
|
579 if (!convo)
|
|
580 continue;
|
|
581 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(convo),
|
|
582 client_entry->nickname, tmp);
|
|
583 }
|
|
584 silc_hash_table_list_reset(&htl);
|
|
585 }
|
|
586
|
|
587 break;
|
|
588
|
|
589 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
|
|
590 break;
|
|
591
|
|
592 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
|
|
593 {
|
|
594 int i;
|
|
595 SilcClientEntry *clients;
|
|
596 SilcUInt32 clients_count;
|
|
597
|
|
598 (void)va_arg(va, void *);
|
|
599 clients = va_arg(va, SilcClientEntry *);
|
|
600 clients_count = va_arg(va, SilcUInt32);
|
|
601
|
|
602 for (i = 0; i < clients_count; i++) {
|
|
603 if (!clients[i]->nickname)
|
|
604 break;
|
|
605
|
|
606 /* Remove from all channels */
|
|
607 silc_hash_table_list(clients[i]->channels, &htl);
|
|
608 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
|
|
609 convo =
|
10246
|
610 gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
611 chu->channel->channel_name, sg->account);
|
8849
|
612 if (!convo)
|
|
613 continue;
|
|
614 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(convo),
|
|
615 clients[i]->nickname,
|
|
616 _("Server signoff"));
|
|
617 }
|
|
618 silc_hash_table_list_reset(&htl);
|
|
619 }
|
|
620 }
|
|
621 break;
|
|
622
|
|
623 case SILC_NOTIFY_TYPE_ERROR:
|
|
624 {
|
|
625 SilcStatus error = va_arg(va, int);
|
|
626 gaim_notify_error(gc, "Error Notify",
|
|
627 silc_get_status_message(error),
|
|
628 NULL);
|
|
629 }
|
|
630 break;
|
|
631
|
|
632 case SILC_NOTIFY_TYPE_WATCH:
|
|
633 {
|
|
634 SilcPublicKey public_key;
|
|
635 unsigned char *pk;
|
|
636 SilcUInt32 pk_len;
|
|
637 char *fingerprint;
|
|
638
|
|
639 client_entry = va_arg(va, SilcClientEntry);
|
|
640 (void)va_arg(va, char *);
|
|
641 mode = va_arg(va, SilcUInt32);
|
|
642 notify = va_arg(va, int);
|
|
643 public_key = va_arg(va, SilcPublicKey);
|
|
644
|
|
645 b = NULL;
|
|
646 if (public_key) {
|
|
647 GaimBlistNode *gnode, *cnode, *bnode;
|
|
648 const char *f;
|
|
649
|
|
650 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
|
|
651 if (!pk)
|
|
652 break;
|
|
653 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
|
|
654 for (i = 0; i < strlen(fingerprint); i++)
|
|
655 if (fingerprint[i] == ' ')
|
|
656 fingerprint[i] = '_';
|
|
657 g_snprintf(buf, sizeof(buf) - 1,
|
|
658 "%s" G_DIR_SEPARATOR_S "clientkeys"
|
|
659 G_DIR_SEPARATOR_S "clientkey_%s.pub",
|
|
660 silcgaim_silcdir(), fingerprint);
|
|
661 silc_free(fingerprint);
|
|
662 silc_free(pk);
|
|
663
|
|
664 /* Find buddy by associated public key */
|
|
665 for (gnode = gaim_get_blist()->root; gnode;
|
|
666 gnode = gnode->next) {
|
|
667 if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
|
|
668 continue;
|
|
669 for (cnode = gnode->child; cnode; cnode = cnode->next) {
|
|
670 if( !GAIM_BLIST_NODE_IS_CONTACT(cnode))
|
|
671 continue;
|
|
672 for (bnode = cnode->child; bnode;
|
|
673 bnode = bnode->next) {
|
|
674 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode))
|
|
675 continue;
|
|
676 b = (GaimBuddy *)bnode;
|
|
677 if (b->account != gc->account)
|
|
678 continue;
|
|
679 f = gaim_blist_node_get_string(bnode, "public-key");
|
|
680 if (!strcmp(f, buf))
|
|
681 goto cont;
|
|
682 }
|
|
683 }
|
|
684 }
|
|
685 }
|
|
686 cont:
|
|
687 if (!b) {
|
|
688 /* Find buddy by nickname */
|
|
689 b = gaim_find_buddy(sg->account, client_entry->nickname);
|
|
690 if (!b) {
|
9272
|
691 gaim_debug_warning("silc", "WATCH for %s, unknown buddy",
|
8849
|
692 client_entry->nickname);
|
|
693 break;
|
|
694 }
|
|
695 }
|
|
696
|
|
697 silc_free(b->proto_data);
|
|
698 b->proto_data = silc_memdup(client_entry->id,
|
|
699 sizeof(*client_entry->id));
|
|
700 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
|
|
701 break;
|
|
702 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
|
|
703 /* See if client was away and is now present */
|
|
704 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
|
|
705 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
|
|
706 SILC_UMODE_DETACHED)) &&
|
|
707 (client_entry->mode & SILC_UMODE_GONE ||
|
|
708 client_entry->mode & SILC_UMODE_INDISPOSED ||
|
|
709 client_entry->mode & SILC_UMODE_BUSY ||
|
|
710 client_entry->mode & SILC_UMODE_PAGE ||
|
|
711 client_entry->mode & SILC_UMODE_DETACHED)) {
|
|
712 client_entry->mode = mode;
|
10050
|
713 gaim_prpl_got_user_status(gaim_buddy_get_account(b), gaim_buddy_get_name(b), SILCGAIM_STATUS_ID_ONLINE, NULL);
|
8849
|
714 }
|
|
715 else if ((mode & SILC_UMODE_GONE) ||
|
|
716 (mode & SILC_UMODE_INDISPOSED) ||
|
|
717 (mode & SILC_UMODE_BUSY) ||
|
|
718 (mode & SILC_UMODE_PAGE) ||
|
|
719 (mode & SILC_UMODE_DETACHED)) {
|
|
720 client_entry->mode = mode;
|
10050
|
721 gaim_prpl_got_user_status(gaim_buddy_get_account(b), gaim_buddy_get_name(b), SILCGAIM_STATUS_ID_OFFLINE, NULL);
|
8849
|
722 }
|
|
723 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
|
|
724 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
|
|
725 notify == SILC_NOTIFY_TYPE_KILLED) {
|
|
726 client_entry->mode = mode;
|
10050
|
727 gaim_prpl_got_user_status(gaim_buddy_get_account(b), gaim_buddy_get_name(b), SILCGAIM_STATUS_ID_OFFLINE, NULL);
|
8849
|
728 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
|
|
729 client_entry->mode = mode;
|
10050
|
730 gaim_prpl_got_user_status(gaim_buddy_get_account(b), gaim_buddy_get_name(b), SILCGAIM_STATUS_ID_ONLINE, NULL);
|
8849
|
731 }
|
|
732 }
|
|
733 break;
|
|
734
|
|
735 default:
|
9353
|
736 gaim_debug_info("silc", "Unhandled notification: %d\n", type);
|
8849
|
737 break;
|
|
738 }
|
|
739
|
|
740 va_end(va);
|
|
741 }
|
|
742
|
|
743
|
|
744 /* Command handler. This function is called always in the command function.
|
|
745 If error occurs it will be called as well. `conn' is the associated
|
|
746 client connection. `cmd_context' is the command context that was
|
|
747 originally sent to the command. `success' is FALSE if error occurred
|
|
748 during command. `command' is the command being processed. It must be
|
|
749 noted that this is not reply from server. This is merely called just
|
|
750 after application has called the command. Just to tell application
|
|
751 that the command really was processed. */
|
|
752
|
|
753 static void
|
|
754 silc_command(SilcClient client, SilcClientConnection conn,
|
|
755 SilcClientCommandContext cmd_context, bool success,
|
|
756 SilcCommand command, SilcStatus status)
|
|
757 {
|
|
758 GaimConnection *gc = client->application;
|
|
759 SilcGaim sg = gc->proto_data;
|
|
760
|
|
761 switch (command) {
|
|
762
|
|
763 case SILC_COMMAND_CMODE:
|
|
764 if (cmd_context->argc == 3 &&
|
|
765 !strcmp(cmd_context->argv[2], "+C"))
|
|
766 sg->chpk = TRUE;
|
|
767 else
|
|
768 sg->chpk = FALSE;
|
|
769 break;
|
|
770
|
|
771 default:
|
|
772 break;
|
|
773 }
|
|
774 }
|
|
775
|
9024
|
776 #if 0
|
8849
|
777 static void
|
|
778 silcgaim_whois_more(SilcClientEntry client_entry, gint id)
|
|
779 {
|
|
780 SilcAttributePayload attr;
|
|
781 SilcAttribute attribute;
|
|
782 char *buf;
|
|
783 GString *s;
|
|
784 SilcVCardStruct vcard;
|
|
785 int i;
|
|
786
|
|
787 if (id != 0)
|
|
788 return;
|
|
789
|
|
790 memset(&vcard, 0, sizeof(vcard));
|
|
791
|
|
792 s = g_string_new("");
|
|
793
|
|
794 silc_dlist_start(client_entry->attrs);
|
|
795 while ((attr = silc_dlist_get(client_entry->attrs)) != SILC_LIST_END) {
|
|
796 attribute = silc_attribute_get_attribute(attr);
|
|
797 switch (attribute) {
|
|
798
|
|
799 case SILC_ATTRIBUTE_USER_INFO:
|
|
800 if (!silc_attribute_get_object(attr, (void *)&vcard,
|
|
801 sizeof(vcard)))
|
|
802 continue;
|
9039
|
803 g_string_append_printf(s, "%s:\n\n", _("Personal Information"));
|
8849
|
804 if (vcard.full_name)
|
9039
|
805 g_string_append_printf(s, "%s:\t\t%s\n",
|
|
806 _("Full Name"),
|
8849
|
807 vcard.full_name);
|
|
808 if (vcard.first_name)
|
9039
|
809 g_string_append_printf(s, "%s:\t%s\n",
|
|
810 _("First Name"),
|
8849
|
811 vcard.first_name);
|
|
812 if (vcard.middle_names)
|
9039
|
813 g_string_append_printf(s, "%s:\t%s\n",
|
|
814 _("Middle Name"),
|
8849
|
815 vcard.middle_names);
|
|
816 if (vcard.family_name)
|
9039
|
817 g_string_append_printf(s, "%s:\t%s\n",
|
|
818 _("Family Name"),
|
8849
|
819 vcard.family_name);
|
|
820 if (vcard.nickname)
|
9039
|
821 g_string_append_printf(s, "%s:\t\t%s\n",
|
|
822 _("Nickname"),
|
8849
|
823 vcard.nickname);
|
|
824 if (vcard.bday)
|
9039
|
825 g_string_append_printf(s, "%s:\t\t%s\n",
|
|
826 _("Birth Day"),
|
8849
|
827 vcard.bday);
|
|
828 if (vcard.title)
|
9039
|
829 g_string_append_printf(s, "%s:\t\t%s\n",
|
|
830 _("Job Title"),
|
8849
|
831 vcard.title);
|
|
832 if (vcard.role)
|
9039
|
833 g_string_append_printf(s, "%s:\t\t%s\n",
|
|
834 _("Job Role"),
|
8849
|
835 vcard.role);
|
|
836 if (vcard.org_name)
|
9039
|
837 g_string_append_printf(s, "%s:\t%s\n",
|
|
838 _("Organization"),
|
8849
|
839 vcard.org_name);
|
|
840 if (vcard.org_unit)
|
9039
|
841 g_string_append_printf(s, "%s:\t\t%s\n",
|
|
842 _("Unit"),
|
8849
|
843 vcard.org_unit);
|
|
844 if (vcard.url)
|
9039
|
845 g_string_append_printf(s, "%s:\t%s\n",
|
|
846 _("Homepage"),
|
8849
|
847 vcard.url);
|
|
848 if (vcard.label)
|
9039
|
849 g_string_append_printf(s, "%s:\t%s\n",
|
|
850 _("Address"),
|
8849
|
851 vcard.label);
|
|
852 for (i = 0; i < vcard.num_tels; i++) {
|
|
853 if (vcard.tels[i].telnum)
|
9039
|
854 g_string_append_printf(s, "%s:\t\t\t%s\n",
|
|
855 _("Phone"),
|
8849
|
856 vcard.tels[i].telnum);
|
|
857 }
|
|
858 for (i = 0; i < vcard.num_emails; i++) {
|
|
859 if (vcard.emails[i].address)
|
9039
|
860 g_string_append_printf(s, "%s:\t\t%s\n",
|
|
861 _("EMail"),
|
8849
|
862 vcard.emails[i].address);
|
|
863 }
|
|
864 if (vcard.note)
|
9039
|
865 g_string_append_printf(s, "\n%s:\t\t%s\n",
|
|
866 _("Note"),
|
8849
|
867 vcard.note);
|
|
868 break;
|
|
869 }
|
|
870 }
|
|
871
|
|
872 buf = g_string_free(s, FALSE);
|
|
873 gaim_notify_info(NULL, _("User Information"), _("User Information"),
|
|
874 buf);
|
|
875 g_free(buf);
|
|
876 }
|
9024
|
877 #endif
|
8849
|
878
|
|
879 /* Command reply handler. This function is called always in the command reply
|
|
880 function. If error occurs it will be called as well. Normal scenario
|
|
881 is that it will be called after the received command data has been parsed
|
|
882 and processed. The function is used to pass the received command data to
|
|
883 the application.
|
|
884
|
|
885 `conn' is the associated client connection. `cmd_payload' is the command
|
|
886 payload data received from server and it can be ignored. It is provided
|
|
887 if the application would like to re-parse the received command data,
|
|
888 however, it must be noted that the data is parsed already by the library
|
|
889 thus the payload can be ignored. `success' is FALSE if error occurred.
|
|
890 In this case arguments are not sent to the application. The `status' is
|
|
891 the command reply status server returned. The `command' is the command
|
|
892 reply being processed. The function has variable argument list and each
|
|
893 command defines the number and type of arguments it passes to the
|
|
894 application (on error they are not sent). */
|
|
895
|
|
896 static void
|
|
897 silc_command_reply(SilcClient client, SilcClientConnection conn,
|
|
898 SilcCommandPayload cmd_payload, bool success,
|
|
899 SilcCommand command, SilcStatus status, ...)
|
|
900 {
|
|
901 GaimConnection *gc = client->application;
|
|
902 SilcGaim sg = gc->proto_data;
|
|
903 GaimConversation *convo;
|
|
904 va_list vp;
|
|
905
|
|
906 va_start(vp, status);
|
|
907
|
|
908 switch (command) {
|
|
909 case SILC_COMMAND_JOIN:
|
|
910 {
|
|
911 SilcChannelEntry channel_entry;
|
|
912
|
|
913 if (!success) {
|
|
914 gaim_notify_error(gc, _("Join Chat"), _("Cannot join channel"),
|
|
915 silc_get_status_message(status));
|
|
916 return;
|
|
917 }
|
|
918
|
|
919 (void)va_arg(vp, char *);
|
|
920 channel_entry = va_arg(vp, SilcChannelEntry);
|
|
921
|
|
922 /* Resolve users on channel */
|
|
923 silc_client_get_clients_by_channel(client, conn, channel_entry,
|
|
924 silcgaim_chat_join_done,
|
|
925 channel_entry);
|
|
926 }
|
|
927 break;
|
|
928
|
|
929 case SILC_COMMAND_LEAVE:
|
|
930 break;
|
|
931
|
|
932 case SILC_COMMAND_USERS:
|
|
933 break;
|
|
934
|
|
935 case SILC_COMMAND_WHOIS:
|
|
936 {
|
|
937 SilcUInt32 idle, mode;
|
|
938 SilcBuffer channels, user_modes;
|
|
939 SilcClientEntry client_entry;
|
10030
|
940 char *buf, tmp[1024], *tmp2, *title;
|
9488
|
941 char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr;
|
8849
|
942 GString *s;
|
|
943
|
|
944 if (!success) {
|
|
945 gaim_notify_error(gc, _("User Information"),
|
9488
|
946 _("Cannot get user information"),
|
|
947 silc_get_status_message(status));
|
8849
|
948 break;
|
|
949 }
|
|
950
|
|
951 client_entry = va_arg(vp, SilcClientEntry);
|
|
952 if (!client_entry->nickname)
|
|
953 break;
|
|
954 (void)va_arg(vp, char *);
|
|
955 (void)va_arg(vp, char *);
|
|
956 (void)va_arg(vp, char *);
|
|
957 channels = va_arg(vp, SilcBuffer);
|
|
958 mode = va_arg(vp, SilcUInt32);
|
|
959 idle = va_arg(vp, SilcUInt32);
|
|
960 (void)va_arg(vp, unsigned char *);
|
|
961 user_modes = va_arg(vp, SilcBuffer);
|
|
962
|
|
963 s = g_string_new("");
|
9488
|
964 tmp2 = gaim_escape_html(client_entry->nickname);
|
|
965 g_string_append_printf(s, "<b>%s:</b> %s", _("Nickname"), tmp2);
|
|
966 g_free(tmp2);
|
|
967 if (client_entry->realname) {
|
|
968 tmp2 = gaim_escape_html(client_entry->realname);
|
|
969 g_string_append_printf(s, "<br><b>%s:</b> %s", _("Realname"), tmp2);
|
|
970 g_free(tmp2);
|
|
971 }
|
|
972 if (client_entry->username) {
|
|
973 tmp2 = gaim_escape_html(client_entry->username);
|
|
974 if (client_entry->hostname)
|
|
975 g_string_append_printf(s, "<br><b>%s:</b> %s@%s", _("Username"), tmp2, client_entry->hostname);
|
|
976 else
|
|
977 g_string_append_printf(s, "<br><b>%s:</b> %s", _("Username"), tmp2);
|
|
978 g_free(tmp2);
|
|
979 }
|
|
980
|
|
981 if (client_entry->mode) {
|
|
982 g_string_append_printf(s, "<br><b>%s:</b> ", _("User Modes"));
|
|
983 memset(tmp, 0, sizeof(tmp));
|
|
984 silcgaim_get_umode_string(client_entry->mode,
|
|
985 tmp, sizeof(tmp) - strlen(tmp));
|
|
986 g_string_append_printf(s, "%s", tmp);
|
|
987 }
|
|
988
|
|
989 silcgaim_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr);
|
|
990 if (moodstr) {
|
|
991 g_string_append_printf(s, "<br><b>%s:</b> %s", _("Mood"), moodstr);
|
|
992 g_free(moodstr);
|
|
993 }
|
|
994
|
|
995 if (statusstr) {
|
|
996 tmp2 = gaim_escape_html(statusstr);
|
|
997 g_string_append_printf(s, "<br><b>%s:</b> %s", _("Status Text"), tmp2);
|
|
998 g_free(statusstr);
|
|
999 g_free(tmp2);
|
|
1000 }
|
|
1001
|
|
1002 if (contactstr) {
|
|
1003 g_string_append_printf(s, "<br><b>%s:</b> %s", _("Preferred Contact"), contactstr);
|
|
1004 g_free(contactstr);
|
|
1005 }
|
|
1006
|
|
1007 if (langstr) {
|
|
1008 g_string_append_printf(s, "<br><b>%s:</b> %s", _("Preferred Language"), langstr);
|
|
1009 g_free(langstr);
|
|
1010 }
|
|
1011
|
|
1012 if (devicestr) {
|
|
1013 g_string_append_printf(s, "<br><b>%s:</b> %s", _("Device"), devicestr);
|
|
1014 g_free(devicestr);
|
|
1015 }
|
|
1016
|
|
1017 if (tzstr) {
|
|
1018 g_string_append_printf(s, "<br><b>%s:</b> %s", _("Timezone"), tzstr);
|
|
1019 g_free(tzstr);
|
|
1020 }
|
|
1021
|
|
1022 if (geostr) {
|
|
1023 g_string_append_printf(s, "<br><b>%s:</b> %s", _("Geolocation"), geostr);
|
|
1024 g_free(geostr);
|
|
1025 }
|
|
1026
|
8849
|
1027 if (client_entry->server)
|
9488
|
1028 g_string_append_printf(s, "<br><b>%s:</b> %s", _("Server"), client_entry->server);
|
8849
|
1029
|
|
1030 if (channels && user_modes) {
|
|
1031 SilcUInt32 *umodes;
|
|
1032 SilcDList list =
|
|
1033 silc_channel_payload_parse_list(channels->data,
|
9488
|
1034 channels->len);
|
8849
|
1035 if (list && silc_get_mode_list(user_modes,
|
9488
|
1036 silc_dlist_count(list),
|
|
1037 &umodes)) {
|
8849
|
1038 SilcChannelPayload entry;
|
|
1039 int i = 0;
|
|
1040
|
9488
|
1041 g_string_append_printf(s, "<br><b>%s:</b> ", _("Currently on"));
|
8849
|
1042 memset(tmp, 0, sizeof(tmp));
|
|
1043 silc_dlist_start(list);
|
|
1044 while ((entry = silc_dlist_get(list))
|
9488
|
1045 != SILC_LIST_END) {
|
8849
|
1046 SilcUInt32 name_len;
|
|
1047 char *m = silc_client_chumode_char(umodes[i++]);
|
|
1048 char *name = silc_channel_get_name(entry, &name_len);
|
|
1049 if (m)
|
|
1050 silc_strncat(tmp, sizeof(tmp) - 1, m, strlen(m));
|
|
1051 silc_strncat(tmp, sizeof(tmp) - 1, name, name_len);
|
|
1052 silc_strncat(tmp, sizeof(tmp) - 1, " ", 1);
|
|
1053 silc_free(m);
|
|
1054
|
|
1055 }
|
9488
|
1056 tmp2 = gaim_escape_html(tmp);
|
|
1057 g_string_append_printf(s, "%s", tmp2);
|
|
1058 g_free(tmp2);
|
8849
|
1059 silc_free(umodes);
|
|
1060 }
|
|
1061 }
|
|
1062
|
|
1063 if (client_entry->public_key) {
|
|
1064 char *fingerprint, *babbleprint;
|
|
1065 unsigned char *pk;
|
|
1066 SilcUInt32 pk_len;
|
|
1067 pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
|
|
1068 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
|
|
1069 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
|
9488
|
1070 g_string_append_printf(s, "<br><b>%s:</b><br>%s", _("Public Key Fingerprint"), fingerprint);
|
|
1071 g_string_append_printf(s, "<br><b>%s:</b><br>%s", _("Public Key Babbleprint"), babbleprint);
|
8849
|
1072 silc_free(fingerprint);
|
|
1073 silc_free(babbleprint);
|
|
1074 silc_free(pk);
|
|
1075 }
|
|
1076
|
|
1077 buf = g_string_free(s, FALSE);
|
|
1078 #if 0 /* XXX for now, let's not show attrs here */
|
|
1079 if (client_entry->attrs)
|
|
1080 gaim_request_action(NULL, _("User Information"),
|
9488
|
1081 _("User Information"),
|
|
1082 buf, 1, client_entry, 2,
|
|
1083 _("OK"), G_CALLBACK(silcgaim_whois_more),
|
|
1084 _("More..."), G_CALLBACK(silcgaim_whois_more));
|
8849
|
1085 else
|
|
1086 #endif
|
10030
|
1087 title = g_strdup_printf(_("Info for %s"), client_entry->nickname);
|
|
1088 gaim_notify_userinfo(gc, client_entry->nickname, title, _("Buddy Information"), NULL, buf, NULL, NULL);
|
|
1089 g_free(title);
|
9488
|
1090 g_free(buf);
|
|
1091 }
|
|
1092 break;
|
|
1093
|
|
1094 case SILC_COMMAND_WHOWAS:
|
|
1095 {
|
|
1096 SilcClientEntry client_entry;
|
10030
|
1097 char *buf, *nickname, *realname, *username, *tmp, *title;
|
9488
|
1098 GString *s;
|
|
1099
|
|
1100 if (!success) {
|
|
1101 gaim_notify_error(gc, _("User Information"),
|
|
1102 _("Cannot get user information"),
|
|
1103 silc_get_status_message(status));
|
|
1104 break;
|
|
1105 }
|
|
1106
|
|
1107 client_entry = va_arg(vp, SilcClientEntry);
|
|
1108 nickname = va_arg(vp, char *);
|
|
1109 username = va_arg(vp, char *);
|
|
1110 realname = va_arg(vp, char *);
|
|
1111 if (!nickname)
|
|
1112 break;
|
|
1113
|
|
1114 s = g_string_new("");
|
|
1115 tmp = gaim_escape_html(nickname);
|
|
1116 g_string_append_printf(s, "<b>%s:</b> %s", _("Nickname"), tmp);
|
|
1117 g_free(tmp);
|
|
1118 if (realname) {
|
|
1119 tmp = gaim_escape_html(realname);
|
|
1120 g_string_append_printf(s, "<br><b>%s:</b> %s", _("Realname"), tmp);
|
|
1121 g_free(tmp);
|
|
1122 }
|
|
1123 if (username) {
|
|
1124 tmp = gaim_escape_html(username);
|
|
1125 if (client_entry && client_entry->hostname)
|
|
1126 g_string_append_printf(s, "<br><b>%s:</b> %s@%s", _("Username"), tmp, client_entry->hostname);
|
|
1127 else
|
|
1128 g_string_append_printf(s, "<br><b>%s:</b> %s", _("Username"), tmp);
|
|
1129 g_free(tmp);
|
|
1130 }
|
|
1131 if (client_entry && client_entry->server)
|
|
1132 g_string_append_printf(s, "<br><b>%s:</b> %s", _("Server"), client_entry->server);
|
|
1133
|
|
1134
|
|
1135 if (client_entry && client_entry->public_key) {
|
|
1136 char *fingerprint, *babbleprint;
|
|
1137 unsigned char *pk;
|
|
1138 SilcUInt32 pk_len;
|
|
1139 pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
|
|
1140 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
|
|
1141 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
|
|
1142 g_string_append_printf(s, "<br><b>%s:</b><br>%s", _("Public Key Fingerprint"), fingerprint);
|
|
1143 g_string_append_printf(s, "<br><b>%s:</b><br>%s", _("Public Key Babbleprint"), babbleprint);
|
|
1144 silc_free(fingerprint);
|
|
1145 silc_free(babbleprint);
|
|
1146 silc_free(pk);
|
|
1147 }
|
|
1148
|
10030
|
1149 title = g_strdup_printf(_("Info for %s"), client_entry->nickname);
|
9488
|
1150 buf = g_string_free(s, FALSE);
|
10030
|
1151 gaim_notify_userinfo(gc, client_entry->nickname, title, _("Buddy Information"), NULL, buf, NULL, NULL);
|
|
1152 g_free(title);
|
8849
|
1153 g_free(buf);
|
|
1154 }
|
|
1155 break;
|
|
1156
|
|
1157 case SILC_COMMAND_DETACH:
|
|
1158 if (!success) {
|
|
1159 gaim_notify_error(gc, _("Detach From Server"), _("Cannot detach"),
|
|
1160 silc_get_status_message(status));
|
|
1161 return;
|
|
1162 }
|
|
1163 break;
|
|
1164
|
|
1165 case SILC_COMMAND_TOPIC:
|
|
1166 {
|
|
1167 SilcChannelEntry channel;
|
|
1168
|
|
1169 if (!success) {
|
|
1170 gaim_notify_error(gc, _("Topic"), _("Cannot set topic"),
|
|
1171 silc_get_status_message(status));
|
|
1172 return;
|
|
1173 }
|
|
1174
|
|
1175 channel = va_arg(vp, SilcChannelEntry);
|
|
1176
|
10246
|
1177 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
1178 channel->channel_name, sg->account);
|
9353
|
1179 if (!convo) {
|
|
1180 gaim_debug_error("silc", "Got a topic for %s, which doesn't exist\n",
|
|
1181 channel->channel_name);
|
8849
|
1182 break;
|
9353
|
1183 }
|
|
1184
|
8849
|
1185 /* Set topic */
|
|
1186 if (channel->topic)
|
|
1187 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(convo), NULL, channel->topic);
|
|
1188 }
|
|
1189 break;
|
|
1190
|
9353
|
1191 case SILC_COMMAND_NICK:
|
|
1192 {
|
|
1193 /* I don't think we should need to do this because the server should
|
|
1194 * be sending a SILC_NOTIFY_TYPE_NICK_CHANGE when we change our own
|
|
1195 * nick, but it isn't, so we deal with it here instead. Stu. */
|
|
1196 SilcClientEntry local_entry;
|
|
1197 SilcHashTableList htl;
|
|
1198 SilcChannelUser chu;
|
|
1199 const char *oldnick;
|
|
1200
|
|
1201 if (!success) {
|
9488
|
1202 gaim_notify_error(gc, _("Nick"), _("Failed to change nickname"),
|
|
1203 silc_get_status_message(status));
|
9353
|
1204 return;
|
|
1205 }
|
|
1206
|
|
1207 local_entry = va_arg(vp, SilcClientEntry);
|
|
1208
|
|
1209 /* Change nick on all channels */
|
|
1210 silc_hash_table_list(local_entry->channels, &htl);
|
|
1211 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
|
10246
|
1212 convo = gaim_find_conversation_with_account(GAIM_CONV_CHAT,
|
|
1213 chu->channel->channel_name, sg->account);
|
|
1214 if (!convo)
|
9353
|
1215 continue;
|
|
1216 oldnick = gaim_conv_chat_get_nick(GAIM_CONV_CHAT(convo));
|
|
1217 if (strcmp(oldnick, local_entry->nickname)) {
|
|
1218 gaim_conv_chat_rename_user(GAIM_CONV_CHAT(convo),
|
|
1219 oldnick, local_entry->nickname);
|
|
1220 gaim_conv_chat_set_nick(GAIM_CONV_CHAT(convo), local_entry->nickname);
|
|
1221 }
|
|
1222 }
|
|
1223 silc_hash_table_list_reset(&htl);
|
9488
|
1224
|
|
1225 gaim_connection_set_display_name(gc, local_entry->nickname);
|
9353
|
1226 }
|
|
1227 break;
|
|
1228
|
8849
|
1229 case SILC_COMMAND_LIST:
|
|
1230 {
|
|
1231 char *topic, *name;
|
|
1232 int usercount;
|
|
1233 GaimRoomlistRoom *room;
|
|
1234
|
|
1235 if (sg->roomlist_canceled)
|
|
1236 break;
|
|
1237
|
|
1238 if (!success) {
|
10091
|
1239 gaim_notify_error(gc, _("Error"), _("Error retrieving room list"),
|
8849
|
1240 silc_get_status_message(status));
|
|
1241 gaim_roomlist_set_in_progress(sg->roomlist, FALSE);
|
|
1242 gaim_roomlist_unref(sg->roomlist);
|
|
1243 sg->roomlist = NULL;
|
|
1244 return;
|
|
1245 }
|
|
1246
|
|
1247 (void)va_arg(vp, SilcChannelEntry);
|
|
1248 name = va_arg(vp, char *);
|
|
1249 topic = va_arg(vp, char *);
|
|
1250 usercount = va_arg(vp, int);
|
|
1251
|
|
1252 room = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_ROOM, name, NULL);
|
|
1253 gaim_roomlist_room_add_field(sg->roomlist, room, name);
|
|
1254 gaim_roomlist_room_add_field(sg->roomlist, room,
|
|
1255 SILC_32_TO_PTR(usercount));
|
|
1256 gaim_roomlist_room_add_field(sg->roomlist, room,
|
|
1257 topic ? topic : "");
|
|
1258 gaim_roomlist_room_add(sg->roomlist, room);
|
|
1259
|
|
1260 if (status == SILC_STATUS_LIST_END ||
|
|
1261 status == SILC_STATUS_OK) {
|
|
1262 gaim_roomlist_set_in_progress(sg->roomlist, FALSE);
|
|
1263 gaim_roomlist_unref(sg->roomlist);
|
|
1264 sg->roomlist = NULL;
|
|
1265 }
|
|
1266 }
|
|
1267 break;
|
|
1268
|
|
1269 case SILC_COMMAND_GETKEY:
|
|
1270 {
|
|
1271 SilcPublicKey public_key;
|
|
1272
|
|
1273 if (!success) {
|
|
1274 gaim_notify_error(gc, _("Get Public Key"),
|
|
1275 _("Cannot fetch the public key"),
|
|
1276 silc_get_status_message(status));
|
|
1277 return;
|
|
1278 }
|
|
1279
|
|
1280 (void)va_arg(vp, SilcUInt32);
|
|
1281 (void)va_arg(vp, void *);
|
|
1282 public_key = va_arg(vp, SilcPublicKey);
|
|
1283
|
|
1284 if (!public_key)
|
|
1285 gaim_notify_error(gc, _("Get Public Key"),
|
|
1286 _("Cannot fetch the public key"),
|
|
1287 _("No public key was received"));
|
|
1288 }
|
|
1289 break;
|
|
1290
|
|
1291 case SILC_COMMAND_INFO:
|
|
1292 {
|
|
1293
|
|
1294 SilcServerEntry server_entry;
|
|
1295 char *server_name;
|
|
1296 char *server_info;
|
9353
|
1297 char tmp[256], *msg;
|
8849
|
1298
|
|
1299 if (!success) {
|
|
1300 gaim_notify_error(gc, _("Server Information"),
|
|
1301 _("Cannot get server information"),
|
|
1302 silc_get_status_message(status));
|
|
1303 return;
|
|
1304 }
|
|
1305
|
|
1306 server_entry = va_arg(vp, SilcServerEntry);
|
|
1307 server_name = va_arg(vp, char *);
|
|
1308 server_info = va_arg(vp, char *);
|
|
1309
|
|
1310 if (server_name && server_info) {
|
|
1311 g_snprintf(tmp, sizeof(tmp), "Server: %s\n%s",
|
|
1312 server_name, server_info);
|
9353
|
1313 msg = g_markup_escape_text(tmp, strlen(tmp));
|
9488
|
1314 gaim_notify_info(gc, NULL, _("Server Information"), msg);
|
9353
|
1315 g_free(msg);
|
8849
|
1316 }
|
|
1317 }
|
|
1318 break;
|
|
1319
|
9488
|
1320 case SILC_COMMAND_STATS:
|
|
1321 {
|
|
1322 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
|
|
1323 my_router_ops, cell_clients, cell_channels, cell_servers,
|
|
1324 clients, channels, servers, routers, server_ops, router_ops;
|
|
1325 SilcUInt32 buffer_length;
|
|
1326 SilcBufferStruct buf;
|
|
1327
|
|
1328 unsigned char *server_stats;
|
|
1329 char *msg;
|
|
1330
|
|
1331 if (!success) {
|
|
1332 gaim_notify_error(gc, _("Server Statistics"),
|
9507
|
1333 _("Cannot get server statistics"),
|
9488
|
1334 silc_get_status_message(status));
|
|
1335 return;
|
|
1336 }
|
|
1337
|
|
1338 server_stats = va_arg(vp, unsigned char *);
|
|
1339 buffer_length = va_arg(vp, SilcUInt32);
|
|
1340 if (!server_stats || !buffer_length) {
|
|
1341 gaim_notify_error(gc, _("Server Statistics"),
|
9645
|
1342 _("No server statistics available"), NULL);
|
9488
|
1343 break;
|
|
1344 }
|
|
1345 silc_buffer_set(&buf, server_stats, buffer_length);
|
|
1346 silc_buffer_unformat(&buf,
|
|
1347 SILC_STR_UI_INT(&starttime),
|
|
1348 SILC_STR_UI_INT(&uptime),
|
|
1349 SILC_STR_UI_INT(&my_clients),
|
|
1350 SILC_STR_UI_INT(&my_channels),
|
|
1351 SILC_STR_UI_INT(&my_server_ops),
|
|
1352 SILC_STR_UI_INT(&my_router_ops),
|
|
1353 SILC_STR_UI_INT(&cell_clients),
|
|
1354 SILC_STR_UI_INT(&cell_channels),
|
|
1355 SILC_STR_UI_INT(&cell_servers),
|
|
1356 SILC_STR_UI_INT(&clients),
|
|
1357 SILC_STR_UI_INT(&channels),
|
|
1358 SILC_STR_UI_INT(&servers),
|
|
1359 SILC_STR_UI_INT(&routers),
|
|
1360 SILC_STR_UI_INT(&server_ops),
|
|
1361 SILC_STR_UI_INT(&router_ops),
|
|
1362 SILC_STR_END);
|
|
1363
|
|
1364 msg = g_strdup_printf(_("Local server start time: %s\n"
|
|
1365 "Local server uptime: %s\n"
|
|
1366 "Local server clients: %d\n"
|
|
1367 "Local server channels: %d\n"
|
|
1368 "Local server operators: %d\n"
|
|
1369 "Local router operators: %d\n"
|
|
1370 "Local cell clients: %d\n"
|
|
1371 "Local cell channels: %d\n"
|
|
1372 "Local cell servers: %d\n"
|
|
1373 "Total clients: %d\n"
|
|
1374 "Total channels: %d\n"
|
|
1375 "Total servers: %d\n"
|
|
1376 "Total routers: %d\n"
|
|
1377 "Total server operators: %d\n"
|
|
1378 "Total router operators: %d\n"),
|
|
1379 silc_get_time(starttime),
|
|
1380 gaim_str_seconds_to_string((int)uptime),
|
|
1381 (int)my_clients, (int)my_channels, (int)my_server_ops, (int)my_router_ops,
|
|
1382 (int)cell_clients, (int)cell_channels, (int)cell_servers,
|
|
1383 (int)clients, (int)channels, (int)servers, (int)routers,
|
|
1384 (int)server_ops, (int)router_ops);
|
|
1385
|
|
1386 gaim_notify_info(gc, NULL,
|
|
1387 _("Network Statistics"), msg);
|
|
1388 g_free(msg);
|
|
1389 }
|
|
1390 break;
|
|
1391
|
|
1392 case SILC_COMMAND_PING:
|
|
1393 {
|
|
1394 if (!success) {
|
|
1395 gaim_notify_error(gc, _("Ping"), _("Ping failed"),
|
|
1396 silc_get_status_message(status));
|
|
1397 return;
|
|
1398 }
|
|
1399
|
|
1400 gaim_notify_info(gc, _("Ping"), _("Ping reply received from server"),
|
|
1401 NULL);
|
|
1402 }
|
|
1403 break;
|
|
1404
|
8849
|
1405 case SILC_COMMAND_KILL:
|
|
1406 if (!success) {
|
|
1407 gaim_notify_error(gc, _("Kill User"),
|
|
1408 _("Could not kill user"),
|
|
1409 silc_get_status_message(status));
|
|
1410 return;
|
|
1411 }
|
|
1412 break;
|
|
1413
|
|
1414 case SILC_COMMAND_CMODE:
|
|
1415 {
|
|
1416 SilcChannelEntry channel_entry;
|
|
1417 SilcBuffer channel_pubkeys;
|
|
1418
|
|
1419 if (!success)
|
|
1420 return;
|
|
1421
|
|
1422 channel_entry = va_arg(vp, SilcChannelEntry);
|
|
1423 (void)va_arg(vp, SilcUInt32);
|
|
1424 (void)va_arg(vp, SilcPublicKey);
|
|
1425 channel_pubkeys = va_arg(vp, SilcBuffer);
|
|
1426
|
|
1427 if (sg->chpk)
|
|
1428 silcgaim_chat_chauth_show(sg, channel_entry, channel_pubkeys);
|
|
1429 }
|
|
1430 break;
|
|
1431
|
|
1432 default:
|
9353
|
1433 if (success)
|
|
1434 gaim_debug_info("silc", "Unhandled command: %d (succeeded)\n", command);
|
|
1435 else
|
|
1436 gaim_debug_info("silc", "Unhandled command: %d (failed: %s)\n", command,
|
|
1437 silc_get_status_message(status));
|
8849
|
1438 break;
|
|
1439 }
|
|
1440
|
|
1441 va_end(vp);
|
|
1442 }
|
|
1443
|
|
1444
|
|
1445 /* Called to indicate that connection was either successfully established
|
|
1446 or connecting failed. This is also the first time application receives
|
9488
|
1447 the SilcClientConnection object which it should save somewhere.
|
8849
|
1448 If the `success' is FALSE the application must always call the function
|
|
1449 silc_client_close_connection. */
|
|
1450
|
|
1451 static void
|
|
1452 silc_connected(SilcClient client, SilcClientConnection conn,
|
|
1453 SilcClientConnectionStatus status)
|
|
1454 {
|
|
1455 GaimConnection *gc = client->application;
|
|
1456 SilcGaim sg = gc->proto_data;
|
|
1457 gboolean reject_watch, block_invites, block_ims;
|
|
1458
|
|
1459 if (!gc) {
|
|
1460 sg->conn = NULL;
|
|
1461 silc_client_close_connection(client, conn);
|
|
1462 return;
|
|
1463 }
|
|
1464
|
|
1465 switch (status) {
|
|
1466 case SILC_CLIENT_CONN_SUCCESS:
|
|
1467 case SILC_CLIENT_CONN_SUCCESS_RESUME:
|
|
1468 gaim_connection_set_state(gc, GAIM_CONNECTED);
|
|
1469 serv_finish_login(gc);
|
|
1470 unlink(silcgaim_session_file(gaim_account_get_username(sg->account)));
|
|
1471
|
|
1472 /* Send any UMODEs configured for account */
|
|
1473 reject_watch = gaim_account_get_bool(sg->account, "reject-watch", FALSE);
|
|
1474 block_invites = gaim_account_get_bool(sg->account, "block-invites", FALSE);
|
|
1475 block_ims = gaim_account_get_bool(sg->account, "block-ims", FALSE);
|
|
1476 if (reject_watch || block_invites || block_ims) {
|
|
1477 char m[5];
|
|
1478 g_snprintf(m, sizeof(m), "+%s%s%s",
|
9488
|
1479 reject_watch ? "w" : "",
|
|
1480 block_invites ? "I" : "",
|
|
1481 block_ims ? "P" : "");
|
8849
|
1482 silc_client_command_call(sg->client, sg->conn, NULL,
|
9488
|
1483 "UMODE", m, NULL);
|
8849
|
1484 }
|
|
1485
|
|
1486 return;
|
|
1487 break;
|
|
1488 case SILC_CLIENT_CONN_ERROR:
|
|
1489 gaim_connection_error(gc, _("Error during connecting to SILC Server"));
|
|
1490 unlink(silcgaim_session_file(gaim_account_get_username(sg->account)));
|
|
1491 break;
|
|
1492
|
|
1493 case SILC_CLIENT_CONN_ERROR_KE:
|
|
1494 gaim_connection_error(gc, _("Key Exchange failed"));
|
|
1495 break;
|
|
1496
|
|
1497 case SILC_CLIENT_CONN_ERROR_AUTH:
|
|
1498 gaim_connection_error(gc, _("Authentication failed"));
|
|
1499 break;
|
|
1500
|
|
1501 case SILC_CLIENT_CONN_ERROR_RESUME:
|
|
1502 gaim_connection_error(gc,
|
8910
|
1503 _("Resuming detached session failed. "
|
8849
|
1504 "Press Reconnect to create new connection."));
|
|
1505 unlink(silcgaim_session_file(gaim_account_get_username(sg->account)));
|
|
1506 break;
|
|
1507
|
|
1508 case SILC_CLIENT_CONN_ERROR_TIMEOUT:
|
9039
|
1509 gaim_connection_error(gc, _("Connection Timeout"));
|
8849
|
1510 break;
|
|
1511 }
|
|
1512
|
|
1513 /* Error */
|
|
1514 sg->conn = NULL;
|
|
1515 silc_client_close_connection(client, conn);
|
|
1516 }
|
|
1517
|
|
1518
|
|
1519 /* Called to indicate that connection was disconnected to the server.
|
|
1520 The `status' may tell the reason of the disconnection, and if the
|
|
1521 `message' is non-NULL it may include the disconnection message
|
|
1522 received from server. */
|
|
1523
|
|
1524 static void
|
|
1525 silc_disconnected(SilcClient client, SilcClientConnection conn,
|
|
1526 SilcStatus status, const char *message)
|
|
1527 {
|
|
1528 GaimConnection *gc = client->application;
|
|
1529 SilcGaim sg = gc->proto_data;
|
|
1530
|
|
1531 if (sg->resuming && !sg->detaching)
|
|
1532 unlink(silcgaim_session_file(gaim_account_get_username(sg->account)));
|
|
1533
|
|
1534 sg->conn = NULL;
|
|
1535
|
|
1536 /* Close the connection */
|
|
1537 if (!sg->detaching)
|
|
1538 gaim_connection_error(gc, _("Disconnected by server"));
|
|
1539 else
|
|
1540 gaim_connection_destroy(gc);
|
|
1541 }
|
|
1542
|
|
1543
|
|
1544 typedef struct {
|
|
1545 SilcGetAuthMeth completion;
|
|
1546 void *context;
|
|
1547 } *SilcGaimGetAuthMethod;
|
|
1548
|
|
1549 /* Callback called when we've received the authentication method information
|
|
1550 from the server after we've requested it. */
|
|
1551
|
|
1552 static void silc_get_auth_method_callback(SilcClient client,
|
|
1553 SilcClientConnection conn,
|
|
1554 SilcAuthMethod auth_meth,
|
|
1555 void *context)
|
|
1556 {
|
|
1557 SilcGaimGetAuthMethod internal = context;
|
|
1558
|
|
1559 switch (auth_meth) {
|
|
1560 case SILC_AUTH_NONE:
|
|
1561 /* No authentication required. */
|
|
1562 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
|
|
1563 break;
|
|
1564
|
|
1565 case SILC_AUTH_PASSWORD:
|
|
1566 /* By returning NULL here the library will ask the passphrase from us
|
|
1567 by calling the silc_ask_passphrase. */
|
|
1568 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
|
|
1569 break;
|
|
1570
|
|
1571 case SILC_AUTH_PUBLIC_KEY:
|
|
1572 /* Do not get the authentication data now, the library will generate
|
|
1573 it using our default key, if we do not provide it here. */
|
|
1574 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
|
|
1575 break;
|
|
1576 }
|
|
1577
|
|
1578 silc_free(internal);
|
|
1579 }
|
|
1580
|
|
1581 /* Find authentication method and authentication data by hostname and
|
|
1582 port. The hostname may be IP address as well. When the authentication
|
|
1583 method has been resolved the `completion' callback with the found
|
|
1584 authentication method and authentication data is called. The `conn'
|
|
1585 may be NULL. */
|
|
1586
|
|
1587 static void
|
|
1588 silc_get_auth_method(SilcClient client, SilcClientConnection conn,
|
|
1589 char *hostname, SilcUInt16 port,
|
|
1590 SilcGetAuthMeth completion, void *context)
|
|
1591 {
|
|
1592 GaimConnection *gc = client->application;
|
|
1593 SilcGaim sg = gc->proto_data;
|
|
1594 SilcGaimGetAuthMethod internal;
|
|
1595
|
|
1596 /* Progress */
|
|
1597 if (sg->resuming)
|
|
1598 gaim_connection_update_progress(gc, _("Resuming session"), 4, 5);
|
|
1599 else
|
|
1600 gaim_connection_update_progress(gc, _("Authenticating connection"), 4, 5);
|
|
1601
|
|
1602 /* Check configuration if we have this connection configured. If we
|
|
1603 have then return that data immediately, as it's faster way. */
|
|
1604 if (gc->account->password && *gc->account->password) {
|
|
1605 completion(TRUE, SILC_AUTH_PASSWORD, gc->account->password,
|
|
1606 strlen(gc->account->password), context);
|
|
1607 return;
|
|
1608 }
|
|
1609 if (gaim_account_get_bool(sg->account, "pubkey-auth", FALSE)) {
|
|
1610 completion(TRUE, SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
|
|
1611 return;
|
|
1612 }
|
|
1613
|
|
1614 /* Resolve the authentication method from server, as we may not know it. */
|
|
1615 internal = silc_calloc(1, sizeof(*internal));
|
|
1616 if (!internal)
|
|
1617 return;
|
|
1618 internal->completion = completion;
|
|
1619 internal->context = context;
|
|
1620 silc_client_request_authentication_method(client, conn,
|
|
1621 silc_get_auth_method_callback,
|
|
1622 internal);
|
|
1623 }
|
|
1624
|
|
1625
|
|
1626 /* Verifies received public key. The `conn_type' indicates which entity
|
|
1627 (server, client etc.) has sent the public key. If user decides to trust
|
|
1628 the application may save the key as trusted public key for later
|
|
1629 use. The `completion' must be called after the public key has been
|
|
1630 verified. */
|
|
1631
|
|
1632 static void
|
|
1633 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
|
|
1634 SilcSocketType conn_type, unsigned char *pk,
|
|
1635 SilcUInt32 pk_len, SilcSKEPKType pk_type,
|
|
1636 SilcVerifyPublicKey completion, void *context)
|
|
1637 {
|
|
1638 GaimConnection *gc = client->application;
|
|
1639 SilcGaim sg = gc->proto_data;
|
|
1640
|
|
1641 if (!sg->conn && (conn_type == SILC_SOCKET_TYPE_SERVER ||
|
|
1642 conn_type == SILC_SOCKET_TYPE_ROUTER)) {
|
|
1643 /* Progress */
|
|
1644 if (sg->resuming)
|
|
1645 gaim_connection_update_progress(gc, _("Resuming session"), 3, 5);
|
|
1646 else
|
|
1647 gaim_connection_update_progress(gc, _("Verifying server public key"),
|
|
1648 3, 5);
|
|
1649 }
|
|
1650
|
|
1651 /* Verify public key */
|
|
1652 silcgaim_verify_public_key(client, conn, NULL, conn_type, pk,
|
|
1653 pk_len, pk_type, completion, context);
|
|
1654 }
|
|
1655
|
|
1656 typedef struct {
|
|
1657 SilcAskPassphrase completion;
|
|
1658 void *context;
|
|
1659 } *SilcGaimAskPassphrase;
|
|
1660
|
|
1661 static void
|
|
1662 silc_ask_passphrase_cb(SilcGaimAskPassphrase internal, const char *passphrase)
|
|
1663 {
|
|
1664 if (!passphrase || !(*passphrase))
|
|
1665 internal->completion(NULL, 0, internal->context);
|
|
1666 else
|
|
1667 internal->completion((unsigned char *)passphrase,
|
|
1668 strlen(passphrase), internal->context);
|
|
1669 silc_free(internal);
|
|
1670 }
|
|
1671
|
|
1672 /* Ask (interact, that is) a passphrase from user. The passphrase is
|
|
1673 returned to the library by calling the `completion' callback with
|
|
1674 the `context'. The returned passphrase SHOULD be in UTF-8 encoded,
|
|
1675 if not then the library will attempt to encode. */
|
|
1676
|
|
1677 static void
|
|
1678 silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
|
|
1679 SilcAskPassphrase completion, void *context)
|
|
1680 {
|
|
1681 SilcGaimAskPassphrase internal = silc_calloc(1, sizeof(*internal));
|
|
1682
|
|
1683 if (!internal)
|
|
1684 return;
|
|
1685 internal->completion = completion;
|
|
1686 internal->context = context;
|
|
1687 gaim_request_input(NULL, _("Passphrase"), NULL,
|
|
1688 _("Passphrase required"), NULL, FALSE, TRUE, NULL,
|
|
1689 _("OK"), G_CALLBACK(silc_ask_passphrase_cb),
|
|
1690 _("Cancel"), G_CALLBACK(silc_ask_passphrase_cb),
|
|
1691 internal);
|
|
1692 }
|
|
1693
|
|
1694
|
|
1695 /* Notifies application that failure packet was received. This is called
|
|
1696 if there is some protocol active in the client. The `protocol' is the
|
|
1697 protocol context. The `failure' is opaque pointer to the failure
|
|
1698 indication. Note, that the `failure' is protocol dependant and
|
|
1699 application must explicitly cast it to correct type. Usually `failure'
|
|
1700 is 32 bit failure type (see protocol specs for all protocol failure
|
|
1701 types). */
|
|
1702
|
|
1703 static void
|
|
1704 silc_failure(SilcClient client, SilcClientConnection conn,
|
|
1705 SilcProtocol protocol, void *failure)
|
|
1706 {
|
|
1707 GaimConnection *gc = client->application;
|
|
1708 char buf[128];
|
|
1709
|
|
1710 memset(buf, 0, sizeof(buf));
|
|
1711
|
|
1712 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
|
|
1713 SilcSKEStatus status = (SilcSKEStatus)SILC_PTR_TO_32(failure);
|
|
1714
|
|
1715 if (status == SILC_SKE_STATUS_BAD_VERSION)
|
|
1716 g_snprintf(buf, sizeof(buf),
|
|
1717 _("Failure: Version mismatch, upgrade your client"));
|
|
1718 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
|
|
1719 g_snprintf(buf, sizeof(buf),
|
|
1720 _("Failure: Remote does not trust/support your public key"));
|
|
1721 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
|
|
1722 g_snprintf(buf, sizeof(buf),
|
|
1723 _("Failure: Remote does not support proposed KE group"));
|
|
1724 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
|
|
1725 g_snprintf(buf, sizeof(buf),
|
|
1726 _("Failure: Remote does not support proposed cipher"));
|
|
1727 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
|
|
1728 g_snprintf(buf, sizeof(buf),
|
|
1729 _("Failure: Remote does not support proposed PKCS"));
|
|
1730 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
|
|
1731 g_snprintf(buf, sizeof(buf),
|
|
1732 _("Failure: Remote does not support proposed hash function"));
|
|
1733 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
|
|
1734 g_snprintf(buf, sizeof(buf),
|
|
1735 _("Failure: Remote does not support proposed HMAC"));
|
|
1736 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
|
|
1737 g_snprintf(buf, sizeof(buf), _("Failure: Incorrect signature"));
|
|
1738 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
|
|
1739 g_snprintf(buf, sizeof(buf), _("Failure: Invalid cookie"));
|
|
1740
|
|
1741 /* Show the error on the progress bar. A more generic error message
|
|
1742 is going to be showed to user after this in the silc_connected. */
|
|
1743 gaim_connection_update_progress(gc, buf, 2, 5);
|
|
1744 }
|
|
1745
|
|
1746 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
|
|
1747 SilcUInt32 err = SILC_PTR_TO_32(failure);
|
|
1748
|
|
1749 if (err == SILC_AUTH_FAILED)
|
|
1750 g_snprintf(buf, sizeof(buf), _("Failure: Authentication failed"));
|
|
1751
|
|
1752 /* Show the error on the progress bar. A more generic error message
|
|
1753 is going to be showed to user after this in the silc_connected. */
|
|
1754 gaim_connection_update_progress(gc, buf, 4, 5);
|
|
1755 }
|
|
1756 }
|
|
1757
|
|
1758 /* Asks whether the user would like to perform the key agreement protocol.
|
|
1759 This is called after we have received an key agreement packet or an
|
|
1760 reply to our key agreement packet. This returns TRUE if the user wants
|
|
1761 the library to perform the key agreement protocol and FALSE if it is not
|
|
1762 desired (application may start it later by calling the function
|
|
1763 silc_client_perform_key_agreement). If TRUE is returned also the
|
|
1764 `completion' and `context' arguments must be set by the application. */
|
|
1765
|
|
1766 static bool
|
|
1767 silc_key_agreement(SilcClient client, SilcClientConnection conn,
|
|
1768 SilcClientEntry client_entry, const char *hostname,
|
|
1769 SilcUInt16 port, SilcKeyAgreementCallback *completion,
|
|
1770 void **context)
|
|
1771 {
|
|
1772 silcgaim_buddy_keyagr_request(client, conn, client_entry, hostname, port);
|
|
1773 *completion = NULL;
|
|
1774 *context = NULL;
|
|
1775 return FALSE;
|
|
1776 }
|
|
1777
|
|
1778
|
|
1779 /* Notifies application that file transfer protocol session is being
|
|
1780 requested by the remote client indicated by the `client_entry' from
|
|
1781 the `hostname' and `port'. The `session_id' is the file transfer
|
|
1782 session and it can be used to either accept or reject the file
|
|
1783 transfer request, by calling the silc_client_file_receive or
|
|
1784 silc_client_file_close, respectively. */
|
|
1785
|
|
1786 static void
|
|
1787 silc_ftp(SilcClient client, SilcClientConnection conn,
|
|
1788 SilcClientEntry client_entry, SilcUInt32 session_id,
|
|
1789 const char *hostname, SilcUInt16 port)
|
|
1790 {
|
|
1791 silcgaim_ftp_request(client, conn, client_entry, session_id,
|
|
1792 hostname, port);
|
|
1793 }
|
|
1794
|
|
1795
|
|
1796 /* Delivers SILC session detachment data indicated by `detach_data' to the
|
|
1797 application. If application has issued SILC_COMMAND_DETACH command
|
|
1798 the client session in the SILC network is not quit. The client remains
|
|
1799 in the network but is detached. The detachment data may be used later
|
|
1800 to resume the session in the SILC Network. The appliation is
|
|
1801 responsible of saving the `detach_data', to for example in a file.
|
|
1802
|
|
1803 The detachment data can be given as argument to the functions
|
|
1804 silc_client_connect_to_server, or silc_client_add_connection when
|
|
1805 creating connection to remote server, inside SilcClientConnectionParams
|
|
1806 structure. If it is provided the client library will attempt to resume
|
|
1807 the session in the network. After the connection is created
|
|
1808 successfully, the application is responsible of setting the user
|
|
1809 interface for user into the same state it was before detaching (showing
|
|
1810 same channels, channel modes, etc). It can do this by fetching the
|
|
1811 information (like joined channels) from the client library. */
|
|
1812
|
|
1813 static void
|
|
1814 silc_detach(SilcClient client, SilcClientConnection conn,
|
|
1815 const unsigned char *detach_data, SilcUInt32 detach_data_len)
|
|
1816 {
|
|
1817 GaimConnection *gc = client->application;
|
|
1818 SilcGaim sg = gc->proto_data;
|
|
1819 const char *file;
|
|
1820
|
|
1821 /* Save the detachment data to file. */
|
|
1822 file = silcgaim_session_file(gaim_account_get_username(sg->account));
|
|
1823 unlink(file);
|
|
1824 silc_file_writefile(file, detach_data, detach_data_len);
|
|
1825 }
|
|
1826
|
|
1827 SilcClientOperations ops = {
|
|
1828 silc_say,
|
|
1829 silc_channel_message,
|
|
1830 silc_private_message,
|
|
1831 silc_notify,
|
|
1832 silc_command,
|
|
1833 silc_command_reply,
|
|
1834 silc_connected,
|
|
1835 silc_disconnected,
|
|
1836 silc_get_auth_method,
|
|
1837 silc_verify_public_key,
|
|
1838 silc_ask_passphrase,
|
|
1839 silc_failure,
|
|
1840 silc_key_agreement,
|
|
1841 silc_ftp,
|
|
1842 silc_detach
|
|
1843 };
|