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 }