Mercurial > pidgin
comparison libpurple/protocols/silc10/wb.c @ 32819:2c6510167895 default tip
propagate from branch 'im.pidgin.pidgin.2.x.y' (head 3315c5dfbd0ad16511bdcf865e5b07c02d07df24)
to branch 'im.pidgin.pidgin' (head cbd1eda6bcbf0565ae7766396bb8f6f419cb6a9a)
author | Elliott Sales de Andrade <qulogic@pidgin.im> |
---|---|
date | Sat, 02 Jun 2012 02:30:49 +0000 |
parents | 01ff09d4a463 071a0e568ac5 |
children |
comparison
equal
deleted
inserted
replaced
32818:01ff09d4a463 | 32819:2c6510167895 |
---|---|
1 /* | |
2 | |
3 wb.c | |
4 | |
5 Author: Pekka Riikonen <priikone@silcnet.org> | |
6 | |
7 Copyright (C) 2005 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 "silcpurple.h" | |
23 #include "wb.h" | |
24 | |
25 /* | |
26 SILC Whiteboard packet: | |
27 | |
28 1 byte command | |
29 2 bytes width | |
30 2 bytes height | |
31 4 bytes brush color | |
32 2 bytes brush size | |
33 n bytes data | |
34 | |
35 Data: | |
36 | |
37 4 bytes x | |
38 4 bytes y | |
39 | |
40 Commands: | |
41 | |
42 0x01 draw | |
43 0x02 clear | |
44 | |
45 MIME: | |
46 | |
47 MIME-Version: 1.0 | |
48 Content-Type: application/x-wb | |
49 Content-Transfer-Encoding: binary | |
50 | |
51 */ | |
52 | |
53 #define SILCPURPLE_WB_MIME "MIME-Version: 1.0\r\nContent-Type: application/x-wb\r\nContent-Transfer-Encoding: binary\r\n\r\n" | |
54 #define SILCPURPLE_WB_HEADER strlen(SILCPURPLE_WB_MIME) + 11 | |
55 | |
56 #define SILCPURPLE_WB_WIDTH 500 | |
57 #define SILCPURPLE_WB_HEIGHT 400 | |
58 #define SILCPURPLE_WB_WIDTH_MAX 1024 | |
59 #define SILCPURPLE_WB_HEIGHT_MAX 1024 | |
60 | |
61 /* Commands */ | |
62 typedef enum { | |
63 SILCPURPLE_WB_DRAW = 0x01, | |
64 SILCPURPLE_WB_CLEAR = 0x02 | |
65 } SilcPurpleWbCommand; | |
66 | |
67 /* Brush size */ | |
68 typedef enum { | |
69 SILCPURPLE_WB_BRUSH_SMALL = 2, | |
70 SILCPURPLE_WB_BRUSH_MEDIUM = 5, | |
71 SILCPURPLE_WB_BRUSH_LARGE = 10 | |
72 } SilcPurpleWbBrushSize; | |
73 | |
74 /* Brush color (XXX Purple should provide default colors) */ | |
75 typedef enum { | |
76 SILCPURPLE_WB_COLOR_BLACK = 0, | |
77 SILCPURPLE_WB_COLOR_RED = 13369344, | |
78 SILCPURPLE_WB_COLOR_GREEN = 52224, | |
79 SILCPURPLE_WB_COLOR_BLUE = 204, | |
80 SILCPURPLE_WB_COLOR_YELLOW = 15658496, | |
81 SILCPURPLE_WB_COLOR_ORANGE = 16737792, | |
82 SILCPURPLE_WB_COLOR_CYAN = 52428, | |
83 SILCPURPLE_WB_COLOR_VIOLET = 5381277, | |
84 SILCPURPLE_WB_COLOR_PURPLE = 13369548, | |
85 SILCPURPLE_WB_COLOR_TAN = 12093547, | |
86 SILCPURPLE_WB_COLOR_BROWN = 5256485, | |
87 SILCPURPLE_WB_COLOR_GREY = 11184810, | |
88 SILCPURPLE_WB_COLOR_WHITE = 16777215 | |
89 } SilcPurpleWbColor; | |
90 | |
91 typedef struct { | |
92 int type; /* 0 = buddy, 1 = channel */ | |
93 union { | |
94 SilcClientEntry client; | |
95 SilcChannelEntry channel; | |
96 } u; | |
97 int width; | |
98 int height; | |
99 int brush_size; | |
100 int brush_color; | |
101 } *SilcPurpleWb; | |
102 | |
103 /* Initialize whiteboard */ | |
104 | |
105 PurpleWhiteboard *silcpurple_wb_init(SilcPurple sg, SilcClientEntry client_entry) | |
106 { | |
107 SilcClientConnection conn; | |
108 PurpleWhiteboard *wb; | |
109 SilcPurpleWb wbs; | |
110 | |
111 conn = sg->conn; | |
112 wb = purple_whiteboard_get_session(sg->account, client_entry->nickname); | |
113 if (!wb) | |
114 wb = purple_whiteboard_create(sg->account, client_entry->nickname, 0); | |
115 if (!wb) | |
116 return NULL; | |
117 | |
118 if (!wb->proto_data) { | |
119 wbs = silc_calloc(1, sizeof(*wbs)); | |
120 if (!wbs) | |
121 return NULL; | |
122 wbs->type = 0; | |
123 wbs->u.client = client_entry; | |
124 wbs->width = SILCPURPLE_WB_WIDTH; | |
125 wbs->height = SILCPURPLE_WB_HEIGHT; | |
126 wbs->brush_size = SILCPURPLE_WB_BRUSH_SMALL; | |
127 wbs->brush_color = SILCPURPLE_WB_COLOR_BLACK; | |
128 wb->proto_data = wbs; | |
129 | |
130 /* Start the whiteboard */ | |
131 purple_whiteboard_start(wb); | |
132 purple_whiteboard_clear(wb); | |
133 } | |
134 | |
135 return wb; | |
136 } | |
137 | |
138 PurpleWhiteboard *silcpurple_wb_init_ch(SilcPurple sg, SilcChannelEntry channel) | |
139 { | |
140 PurpleWhiteboard *wb; | |
141 SilcPurpleWb wbs; | |
142 | |
143 wb = purple_whiteboard_get_session(sg->account, channel->channel_name); | |
144 if (!wb) | |
145 wb = purple_whiteboard_create(sg->account, channel->channel_name, 0); | |
146 if (!wb) | |
147 return NULL; | |
148 | |
149 if (!wb->proto_data) { | |
150 wbs = silc_calloc(1, sizeof(*wbs)); | |
151 if (!wbs) | |
152 return NULL; | |
153 wbs->type = 1; | |
154 wbs->u.channel = channel; | |
155 wbs->width = SILCPURPLE_WB_WIDTH; | |
156 wbs->height = SILCPURPLE_WB_HEIGHT; | |
157 wbs->brush_size = SILCPURPLE_WB_BRUSH_SMALL; | |
158 wbs->brush_color = SILCPURPLE_WB_COLOR_BLACK; | |
159 wb->proto_data = wbs; | |
160 | |
161 /* Start the whiteboard */ | |
162 purple_whiteboard_start(wb); | |
163 purple_whiteboard_clear(wb); | |
164 } | |
165 | |
166 return wb; | |
167 } | |
168 | |
169 static void | |
170 silcpurple_wb_parse(SilcPurpleWb wbs, PurpleWhiteboard *wb, | |
171 unsigned char *message, SilcUInt32 message_len) | |
172 { | |
173 SilcUInt8 command; | |
174 SilcUInt16 width, height, brush_size; | |
175 SilcUInt32 brush_color, x, y, dx, dy; | |
176 SilcBufferStruct buf; | |
177 int ret; | |
178 | |
179 /* Parse the packet */ | |
180 silc_buffer_set(&buf, message, message_len); | |
181 ret = silc_buffer_unformat(&buf, | |
182 SILC_STR_UI_CHAR(&command), | |
183 SILC_STR_UI_SHORT(&width), | |
184 SILC_STR_UI_SHORT(&height), | |
185 SILC_STR_UI_INT(&brush_color), | |
186 SILC_STR_UI_SHORT(&brush_size), | |
187 SILC_STR_END); | |
188 if (ret < 0) | |
189 return; | |
190 silc_buffer_pull(&buf, ret); | |
191 | |
192 /* Update whiteboard if its dimensions changed */ | |
193 if (width != wbs->width || height != wbs->height) | |
194 silcpurple_wb_set_dimensions(wb, height, width); | |
195 | |
196 if (command == SILCPURPLE_WB_DRAW) { | |
197 /* Parse data and draw it */ | |
198 ret = silc_buffer_unformat(&buf, | |
199 SILC_STR_UI_INT(&dx), | |
200 SILC_STR_UI_INT(&dy), | |
201 SILC_STR_END); | |
202 if (ret < 0) | |
203 return; | |
204 silc_buffer_pull(&buf, 8); | |
205 x = dx; | |
206 y = dy; | |
207 while (buf.len > 0) { | |
208 ret = silc_buffer_unformat(&buf, | |
209 SILC_STR_UI_INT(&dx), | |
210 SILC_STR_UI_INT(&dy), | |
211 SILC_STR_END); | |
212 if (ret < 0) | |
213 return; | |
214 silc_buffer_pull(&buf, 8); | |
215 | |
216 purple_whiteboard_draw_line(wb, x, y, x + dx, y + dy, | |
217 brush_color, brush_size); | |
218 x += dx; | |
219 y += dy; | |
220 } | |
221 } | |
222 | |
223 if (command == SILCPURPLE_WB_CLEAR) | |
224 purple_whiteboard_clear(wb); | |
225 } | |
226 | |
227 typedef struct { | |
228 unsigned char *message; | |
229 SilcUInt32 message_len; | |
230 SilcPurple sg; | |
231 SilcClientEntry sender; | |
232 SilcChannelEntry channel; | |
233 } *SilcPurpleWbRequest; | |
234 | |
235 static void | |
236 silcpurple_wb_request_cb(SilcPurpleWbRequest req, gint id) | |
237 { | |
238 PurpleWhiteboard *wb; | |
239 | |
240 if (id != 1) | |
241 goto out; | |
242 | |
243 if (!req->channel) | |
244 wb = silcpurple_wb_init(req->sg, req->sender); | |
245 else | |
246 wb = silcpurple_wb_init_ch(req->sg, req->channel); | |
247 | |
248 silcpurple_wb_parse(wb->proto_data, wb, req->message, req->message_len); | |
249 | |
250 out: | |
251 silc_free(req->message); | |
252 silc_free(req); | |
253 } | |
254 | |
255 static void | |
256 silcpurple_wb_request(SilcClient client, const unsigned char *message, | |
257 SilcUInt32 message_len, SilcClientEntry sender, | |
258 SilcChannelEntry channel) | |
259 { | |
260 char tmp[128]; | |
261 SilcPurpleWbRequest req; | |
262 PurpleConnection *gc; | |
263 SilcPurple sg; | |
264 | |
265 gc = client->application; | |
266 sg = gc->proto_data; | |
267 | |
268 /* Open whiteboard automatically if requested */ | |
269 if (purple_account_get_bool(sg->account, "open-wb", FALSE)) { | |
270 PurpleWhiteboard *wb; | |
271 | |
272 if (!channel) | |
273 wb = silcpurple_wb_init(sg, sender); | |
274 else | |
275 wb = silcpurple_wb_init_ch(sg, channel); | |
276 | |
277 silcpurple_wb_parse(wb->proto_data, wb, (unsigned char *)message, | |
278 message_len); | |
279 return; | |
280 } | |
281 | |
282 /* Close any previous unaccepted requests */ | |
283 purple_request_close_with_handle(sender); | |
284 | |
285 if (!channel) { | |
286 g_snprintf(tmp, sizeof(tmp), | |
287 _("%s sent message to whiteboard. Would you like " | |
288 "to open the whiteboard?"), sender->nickname); | |
289 } else { | |
290 g_snprintf(tmp, sizeof(tmp), | |
291 _("%s sent message to whiteboard on %s channel. " | |
292 "Would you like to open the whiteboard?"), | |
293 sender->nickname, channel->channel_name); | |
294 } | |
295 | |
296 req = silc_calloc(1, sizeof(*req)); | |
297 if (!req) | |
298 return; | |
299 req->message = silc_memdup(message, message_len); | |
300 req->message_len = message_len; | |
301 req->sender = sender; | |
302 req->channel = channel; | |
303 req->sg = sg; | |
304 | |
305 purple_request_action(sender, _("Whiteboard"), tmp, NULL, 1, | |
306 sg->account, sender->nickname, NULL, req, 2, | |
307 _("Yes"), G_CALLBACK(silcpurple_wb_request_cb), | |
308 _("No"), G_CALLBACK(silcpurple_wb_request_cb)); | |
309 } | |
310 | |
311 /* Process incoming whiteboard message */ | |
312 | |
313 void silcpurple_wb_receive(SilcClient client, SilcClientConnection conn, | |
314 SilcClientEntry sender, SilcMessagePayload payload, | |
315 SilcMessageFlags flags, const unsigned char *message, | |
316 SilcUInt32 message_len) | |
317 { | |
318 SilcPurple sg; | |
319 PurpleConnection *gc; | |
320 PurpleWhiteboard *wb; | |
321 SilcPurpleWb wbs; | |
322 | |
323 gc = client->application; | |
324 sg = gc->proto_data; | |
325 | |
326 wb = purple_whiteboard_get_session(sg->account, sender->nickname); | |
327 if (!wb) { | |
328 /* Ask user if they want to open the whiteboard */ | |
329 silcpurple_wb_request(client, message, message_len, | |
330 sender, NULL); | |
331 return; | |
332 } | |
333 | |
334 wbs = wb->proto_data; | |
335 silcpurple_wb_parse(wbs, wb, (unsigned char *)message, message_len); | |
336 } | |
337 | |
338 /* Process incoming whiteboard message on channel */ | |
339 | |
340 void silcpurple_wb_receive_ch(SilcClient client, SilcClientConnection conn, | |
341 SilcClientEntry sender, SilcChannelEntry channel, | |
342 SilcMessagePayload payload, | |
343 SilcMessageFlags flags, | |
344 const unsigned char *message, | |
345 SilcUInt32 message_len) | |
346 { | |
347 SilcPurple sg; | |
348 PurpleConnection *gc; | |
349 PurpleWhiteboard *wb; | |
350 SilcPurpleWb wbs; | |
351 | |
352 gc = client->application; | |
353 sg = gc->proto_data; | |
354 | |
355 wb = purple_whiteboard_get_session(sg->account, channel->channel_name); | |
356 if (!wb) { | |
357 /* Ask user if they want to open the whiteboard */ | |
358 silcpurple_wb_request(client, message, message_len, | |
359 sender, channel); | |
360 return; | |
361 } | |
362 | |
363 wbs = wb->proto_data; | |
364 silcpurple_wb_parse(wbs, wb, (unsigned char *)message, message_len); | |
365 } | |
366 | |
367 /* Send whiteboard message */ | |
368 | |
369 void silcpurple_wb_send(PurpleWhiteboard *wb, GList *draw_list) | |
370 { | |
371 SilcPurpleWb wbs = wb->proto_data; | |
372 SilcBuffer packet; | |
373 GList *list; | |
374 int len; | |
375 PurpleConnection *gc; | |
376 SilcPurple sg; | |
377 | |
378 g_return_if_fail(draw_list); | |
379 gc = purple_account_get_connection(wb->account); | |
380 g_return_if_fail(gc); | |
381 sg = gc->proto_data; | |
382 g_return_if_fail(sg); | |
383 | |
384 len = SILCPURPLE_WB_HEADER; | |
385 for (list = draw_list; list; list = list->next) | |
386 len += 4; | |
387 | |
388 packet = silc_buffer_alloc_size(len); | |
389 if (!packet) | |
390 return; | |
391 | |
392 /* Assmeble packet */ | |
393 silc_buffer_format(packet, | |
394 SILC_STR_UI32_STRING(SILCPURPLE_WB_MIME), | |
395 SILC_STR_UI_CHAR(SILCPURPLE_WB_DRAW), | |
396 SILC_STR_UI_SHORT(wbs->width), | |
397 SILC_STR_UI_SHORT(wbs->height), | |
398 SILC_STR_UI_INT(wbs->brush_color), | |
399 SILC_STR_UI_SHORT(wbs->brush_size), | |
400 SILC_STR_END); | |
401 silc_buffer_pull(packet, SILCPURPLE_WB_HEADER); | |
402 for (list = draw_list; list; list = list->next) { | |
403 silc_buffer_format(packet, | |
404 SILC_STR_UI_INT(GPOINTER_TO_INT(list->data)), | |
405 SILC_STR_END); | |
406 silc_buffer_pull(packet, 4); | |
407 } | |
408 | |
409 /* Send the message */ | |
410 if (wbs->type == 0) { | |
411 /* Private message */ | |
412 silc_client_send_private_message(sg->client, sg->conn, | |
413 wbs->u.client, | |
414 SILC_MESSAGE_FLAG_DATA, | |
415 packet->head, len, TRUE); | |
416 } else if (wbs->type == 1) { | |
417 /* Channel message. Channel private keys are not supported. */ | |
418 silc_client_send_channel_message(sg->client, sg->conn, | |
419 wbs->u.channel, NULL, | |
420 SILC_MESSAGE_FLAG_DATA, | |
421 packet->head, len, TRUE); | |
422 } | |
423 | |
424 silc_buffer_free(packet); | |
425 } | |
426 | |
427 /* Purple Whiteboard operations */ | |
428 | |
429 void silcpurple_wb_start(PurpleWhiteboard *wb) | |
430 { | |
431 /* Nothing here. Everything is in initialization */ | |
432 } | |
433 | |
434 void silcpurple_wb_end(PurpleWhiteboard *wb) | |
435 { | |
436 silc_free(wb->proto_data); | |
437 wb->proto_data = NULL; | |
438 } | |
439 | |
440 void silcpurple_wb_get_dimensions(const PurpleWhiteboard *wb, int *width, int *height) | |
441 { | |
442 SilcPurpleWb wbs = wb->proto_data; | |
443 *width = wbs->width; | |
444 *height = wbs->height; | |
445 } | |
446 | |
447 void silcpurple_wb_set_dimensions(PurpleWhiteboard *wb, int width, int height) | |
448 { | |
449 SilcPurpleWb wbs = wb->proto_data; | |
450 wbs->width = width > SILCPURPLE_WB_WIDTH_MAX ? SILCPURPLE_WB_WIDTH_MAX : | |
451 width; | |
452 wbs->height = height > SILCPURPLE_WB_HEIGHT_MAX ? SILCPURPLE_WB_HEIGHT_MAX : | |
453 height; | |
454 | |
455 /* Update whiteboard */ | |
456 purple_whiteboard_set_dimensions(wb, wbs->width, wbs->height); | |
457 } | |
458 | |
459 void silcpurple_wb_get_brush(const PurpleWhiteboard *wb, int *size, int *color) | |
460 { | |
461 SilcPurpleWb wbs = wb->proto_data; | |
462 *size = wbs->brush_size; | |
463 *color = wbs->brush_color; | |
464 } | |
465 | |
466 void silcpurple_wb_set_brush(PurpleWhiteboard *wb, int size, int color) | |
467 { | |
468 SilcPurpleWb wbs = wb->proto_data; | |
469 wbs->brush_size = size; | |
470 wbs->brush_color = color; | |
471 | |
472 /* Update whiteboard */ | |
473 purple_whiteboard_set_brush(wb, size, color); | |
474 } | |
475 | |
476 void silcpurple_wb_clear(PurpleWhiteboard *wb) | |
477 { | |
478 SilcPurpleWb wbs = wb->proto_data; | |
479 SilcBuffer packet; | |
480 int len; | |
481 PurpleConnection *gc; | |
482 SilcPurple sg; | |
483 | |
484 gc = purple_account_get_connection(wb->account); | |
485 g_return_if_fail(gc); | |
486 sg = gc->proto_data; | |
487 g_return_if_fail(sg); | |
488 | |
489 len = SILCPURPLE_WB_HEADER; | |
490 packet = silc_buffer_alloc_size(len); | |
491 if (!packet) | |
492 return; | |
493 | |
494 /* Assmeble packet */ | |
495 silc_buffer_format(packet, | |
496 SILC_STR_UI32_STRING(SILCPURPLE_WB_MIME), | |
497 SILC_STR_UI_CHAR(SILCPURPLE_WB_CLEAR), | |
498 SILC_STR_UI_SHORT(wbs->width), | |
499 SILC_STR_UI_SHORT(wbs->height), | |
500 SILC_STR_UI_INT(wbs->brush_color), | |
501 SILC_STR_UI_SHORT(wbs->brush_size), | |
502 SILC_STR_END); | |
503 | |
504 /* Send the message */ | |
505 if (wbs->type == 0) { | |
506 /* Private message */ | |
507 silc_client_send_private_message(sg->client, sg->conn, | |
508 wbs->u.client, | |
509 SILC_MESSAGE_FLAG_DATA, | |
510 packet->head, len, TRUE); | |
511 } else if (wbs->type == 1) { | |
512 /* Channel message */ | |
513 silc_client_send_channel_message(sg->client, sg->conn, | |
514 wbs->u.channel, NULL, | |
515 SILC_MESSAGE_FLAG_DATA, | |
516 packet->head, len, TRUE); | |
517 } | |
518 | |
519 silc_buffer_free(packet); | |
520 } |