|
12058
|
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 "silcgaim.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 SILCGAIM_WB_MIME "MIME-Version: 1.0\r\nContent-Type: application/x-wb\r\nContent-Transfer-Encoding: binary\r\n\r\n"
|
|
|
54 #define SILCGAIM_WB_HEADER strlen(SILCGAIM_WB_MIME) + 11
|
|
|
55
|
|
|
56 #define SILCGAIM_WB_WIDTH 500
|
|
|
57 #define SILCGAIM_WB_HEIGHT 400
|
|
|
58 #define SILCGAIM_WB_WIDTH_MAX 1024
|
|
|
59 #define SILCGAIM_WB_HEIGHT_MAX 1024
|
|
|
60
|
|
|
61 /* Commands */
|
|
|
62 typedef enum {
|
|
|
63 SILCGAIM_WB_DRAW = 0x01,
|
|
|
64 SILCGAIM_WB_CLEAR = 0x02,
|
|
|
65 } SilcGaimWbCommand;
|
|
|
66
|
|
|
67 /* Brush size */
|
|
|
68 typedef enum {
|
|
|
69 SILCGAIM_WB_BRUSH_SMALL = 2,
|
|
|
70 SILCGAIM_WB_BRUSH_MEDIUM = 5,
|
|
|
71 SILCGAIM_WB_BRUSH_LARGE = 10,
|
|
|
72 } SilcGaimWbBrushSize;
|
|
|
73
|
|
|
74 /* Brush color (XXX Gaim should provide default colors) */
|
|
|
75 typedef enum {
|
|
|
76 SILCGAIM_WB_COLOR_BLACK = 0,
|
|
|
77 SILCGAIM_WB_COLOR_RED = 13369344,
|
|
|
78 SILCGAIM_WB_COLOR_GREEN = 52224,
|
|
|
79 SILCGAIM_WB_COLOR_BLUE = 204,
|
|
|
80 SILCGAIM_WB_COLOR_YELLOW = 15658496,
|
|
|
81 SILCGAIM_WB_COLOR_ORANGE = 16737792,
|
|
|
82 SILCGAIM_WB_COLOR_CYAN = 52428,
|
|
|
83 SILCGAIM_WB_COLOR_VIOLET = 5381277,
|
|
|
84 SILCGAIM_WB_COLOR_PURPLE = 13369548,
|
|
|
85 SILCGAIM_WB_COLOR_TAN = 12093547,
|
|
|
86 SILCGAIM_WB_COLOR_BROWN = 5256485,
|
|
|
87 SILCGAIM_WB_COLOR_GREY = 11184810,
|
|
|
88 SILCGAIM_WB_COLOR_WHITE = 16777215,
|
|
|
89 } SilcGaimWbColor;
|
|
|
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 } *SilcGaimWb;
|
|
|
102
|
|
|
103 /* Initialize whiteboard */
|
|
|
104
|
|
|
105 GaimWhiteboard *silcgaim_wb_init(SilcGaim sg, SilcClientEntry client_entry)
|
|
|
106 {
|
|
|
107 SilcClientConnection conn;
|
|
|
108 GaimWhiteboard *wb;
|
|
|
109 SilcGaimWb wbs;
|
|
|
110
|
|
|
111 conn = sg->conn;
|
|
|
112 wb = gaim_whiteboard_get_session(sg->account, client_entry->nickname);
|
|
|
113 if (!wb)
|
|
|
114 wb = gaim_whiteboard_create(sg->account, client_entry->nickname,
|
|
|
115 0);
|
|
|
116 if (!wb)
|
|
|
117 return NULL;
|
|
|
118
|
|
|
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 = SILCGAIM_WB_WIDTH;
|
|
|
125 wbs->height = SILCGAIM_WB_HEIGHT;
|
|
|
126 wbs->brush_size = SILCGAIM_WB_BRUSH_SMALL;
|
|
|
127 wbs->brush_color = SILCGAIM_WB_COLOR_BLACK;
|
|
|
128 wb->proto_data = wbs;
|
|
|
129
|
|
|
130 /* Start the whiteboard */
|
|
|
131 gaim_whiteboard_start(wb);
|
|
|
132 gaim_whiteboard_clear(wb);
|
|
|
133
|
|
|
134 return wb;
|
|
|
135 }
|
|
|
136
|
|
|
137 GaimWhiteboard *silcgaim_wb_init_ch(SilcGaim sg, SilcChannelEntry channel)
|
|
|
138 {
|
|
|
139 GaimWhiteboard *wb;
|
|
|
140 SilcGaimWb wbs;
|
|
|
141
|
|
|
142 wb = gaim_whiteboard_get_session(sg->account, channel->channel_name);
|
|
|
143 if (!wb)
|
|
|
144 wb = gaim_whiteboard_create(sg->account, channel->channel_name,
|
|
|
145 0);
|
|
|
146 if (!wb)
|
|
|
147 return NULL;
|
|
|
148
|
|
|
149 wbs = silc_calloc(1, sizeof(*wbs));
|
|
|
150 if (!wbs)
|
|
|
151 return NULL;
|
|
|
152 wbs->type = 1;
|
|
|
153 wbs->u.channel = channel;
|
|
|
154 wbs->width = SILCGAIM_WB_WIDTH;
|
|
|
155 wbs->height = SILCGAIM_WB_HEIGHT;
|
|
|
156 wbs->brush_size = SILCGAIM_WB_BRUSH_SMALL;
|
|
|
157 wbs->brush_color = SILCGAIM_WB_COLOR_BLACK;
|
|
|
158 wb->proto_data = wbs;
|
|
|
159
|
|
|
160 /* Start the whiteboard */
|
|
|
161 gaim_whiteboard_start(wb);
|
|
|
162 gaim_whiteboard_clear(wb);
|
|
|
163
|
|
|
164 return wb;
|
|
|
165 }
|
|
|
166
|
|
|
167 static void
|
|
|
168 silcgaim_wb_parse(SilcGaimWb wbs, GaimWhiteboard *wb,
|
|
|
169 unsigned char *message, SilcUInt32 message_len)
|
|
|
170 {
|
|
|
171 SilcUInt8 command;
|
|
|
172 SilcUInt16 width, height, brush_size;
|
|
|
173 SilcUInt32 brush_color, x, y, dx, dy;
|
|
|
174 SilcBufferStruct buf;
|
|
|
175 int ret;
|
|
|
176
|
|
|
177 /* Parse the packet */
|
|
|
178 silc_buffer_set(&buf, message, message_len);
|
|
|
179 ret = silc_buffer_unformat(&buf,
|
|
|
180 SILC_STR_UI_CHAR(&command),
|
|
|
181 SILC_STR_UI_SHORT(&width),
|
|
|
182 SILC_STR_UI_SHORT(&height),
|
|
|
183 SILC_STR_UI_INT(&brush_color),
|
|
|
184 SILC_STR_UI_SHORT(&brush_size),
|
|
|
185 SILC_STR_END);
|
|
|
186 if (ret < 0)
|
|
|
187 return;
|
|
|
188 silc_buffer_pull(&buf, ret);
|
|
|
189
|
|
|
190 /* Update whiteboard if its dimensions changed */
|
|
|
191 if (width != wbs->width || height != wbs->height)
|
|
|
192 silcgaim_wb_set_dimensions(wb, height, width);
|
|
|
193
|
|
|
194 if (command == SILCGAIM_WB_DRAW) {
|
|
|
195 /* Parse data and draw it */
|
|
|
196 ret = silc_buffer_unformat(&buf,
|
|
|
197 SILC_STR_UI_INT(&dx),
|
|
|
198 SILC_STR_UI_INT(&dy),
|
|
|
199 SILC_STR_END);
|
|
|
200 if (ret < 0)
|
|
|
201 return;
|
|
|
202 silc_buffer_pull(&buf, 8);
|
|
|
203 x = dx;
|
|
|
204 y = dy;
|
|
|
205 while (buf.len > 0) {
|
|
|
206 ret = silc_buffer_unformat(&buf,
|
|
|
207 SILC_STR_UI_INT(&dx),
|
|
|
208 SILC_STR_UI_INT(&dy),
|
|
|
209 SILC_STR_END);
|
|
|
210 if (ret < 0)
|
|
|
211 return;
|
|
|
212 silc_buffer_pull(&buf, 8);
|
|
|
213
|
|
|
214 gaim_whiteboard_draw_line(wb, x, y, x + dx, y + dy,
|
|
|
215 brush_color, brush_size);
|
|
|
216 x += dx;
|
|
|
217 y += dy;
|
|
|
218 }
|
|
|
219 }
|
|
|
220
|
|
|
221 if (command == SILCGAIM_WB_CLEAR)
|
|
|
222 gaim_whiteboard_clear(wb);
|
|
|
223 }
|
|
|
224
|
|
|
225 typedef struct {
|
|
|
226 unsigned char *message;
|
|
|
227 SilcUInt32 message_len;
|
|
|
228 SilcGaim sg;
|
|
|
229 SilcClientEntry sender;
|
|
|
230 SilcChannelEntry channel;
|
|
|
231 } *SilcGaimWbRequest;
|
|
|
232
|
|
|
233 static void
|
|
|
234 silcgaim_wb_request_cb(SilcGaimWbRequest req, gint id)
|
|
|
235 {
|
|
|
236 GaimWhiteboard *wb;
|
|
|
237
|
|
|
238 if (id != 1)
|
|
|
239 goto out;
|
|
|
240
|
|
|
241 if (!req->channel)
|
|
|
242 wb = silcgaim_wb_init(req->sg, req->sender);
|
|
|
243 else
|
|
|
244 wb = silcgaim_wb_init_ch(req->sg, req->channel);
|
|
|
245
|
|
|
246 silcgaim_wb_parse(wb->proto_data, wb, req->message, req->message_len);
|
|
|
247
|
|
|
248 out:
|
|
|
249 silc_free(req->message);
|
|
|
250 silc_free(req);
|
|
|
251 }
|
|
|
252
|
|
|
253 static void
|
|
|
254 silcgaim_wb_request(SilcClient client, const unsigned char *message,
|
|
|
255 SilcUInt32 message_len, SilcClientEntry sender,
|
|
|
256 SilcChannelEntry channel)
|
|
|
257 {
|
|
|
258 char tmp[128];
|
|
|
259 SilcGaimWbRequest req;
|
|
|
260 GaimConnection *gc;
|
|
|
261 SilcGaim sg;
|
|
|
262
|
|
|
263 if (!channel) {
|
|
|
264 g_snprintf(tmp, sizeof(tmp),
|
|
|
265 _("%s sent message to whiteboard. Would you like "
|
|
|
266 "to open the whiteboard?"), sender->nickname);
|
|
|
267 } else {
|
|
|
268 g_snprintf(tmp, sizeof(tmp),
|
|
|
269 _("%s sent message to whiteboard on %s channel. "
|
|
|
270 "Would you like to open the whiteboard?"),
|
|
|
271 sender->nickname, channel->channel_name);
|
|
|
272 }
|
|
|
273
|
|
|
274 gc = client->application;
|
|
|
275 sg = gc->proto_data;
|
|
|
276
|
|
|
277 req = silc_calloc(1, sizeof(*req));
|
|
|
278 if (!req)
|
|
|
279 return;
|
|
|
280 req->message = silc_memdup(message, message_len);
|
|
|
281 req->message_len = message_len;
|
|
|
282 req->sender = sender;
|
|
|
283 req->channel = channel;
|
|
|
284 req->sg = sg;
|
|
|
285
|
|
|
286 gaim_request_action(gc, _("Whiteboard"), tmp, NULL, 1, req, 2,
|
|
|
287 _("Yes"), G_CALLBACK(silcgaim_wb_request_cb),
|
|
|
288 _("No"), G_CALLBACK(silcgaim_wb_request_cb));
|
|
|
289 }
|
|
|
290
|
|
|
291 /* Process incoming whiteboard message */
|
|
|
292
|
|
|
293 void silcgaim_wb_receive(SilcClient client, SilcClientConnection conn,
|
|
|
294 SilcClientEntry sender, SilcMessagePayload payload,
|
|
|
295 SilcMessageFlags flags, const unsigned char *message,
|
|
|
296 SilcUInt32 message_len)
|
|
|
297 {
|
|
|
298 SilcGaim sg;
|
|
|
299 GaimConnection *gc;
|
|
|
300 GaimWhiteboard *wb;
|
|
|
301 SilcGaimWb wbs;
|
|
|
302
|
|
|
303 gc = client->application;
|
|
|
304 sg = gc->proto_data;
|
|
|
305
|
|
|
306 wb = gaim_whiteboard_get_session(sg->account, sender->nickname);
|
|
|
307 if (!wb) {
|
|
|
308 /* Ask user if they want to open the whiteboard */
|
|
|
309 silcgaim_wb_request(client, message, message_len,
|
|
|
310 sender, NULL);
|
|
|
311 return;
|
|
|
312 }
|
|
|
313
|
|
|
314 wbs = wb->proto_data;
|
|
|
315 silcgaim_wb_parse(wbs, wb, (unsigned char *)message, message_len);
|
|
|
316 }
|
|
|
317
|
|
|
318 /* Process incoming whiteboard message on channel */
|
|
|
319
|
|
|
320 void silcgaim_wb_receive_ch(SilcClient client, SilcClientConnection conn,
|
|
|
321 SilcClientEntry sender, SilcChannelEntry channel,
|
|
|
322 SilcMessagePayload payload,
|
|
|
323 SilcMessageFlags flags,
|
|
|
324 const unsigned char *message,
|
|
|
325 SilcUInt32 message_len)
|
|
|
326 {
|
|
|
327 SilcGaim sg;
|
|
|
328 GaimConnection *gc;
|
|
|
329 GaimWhiteboard *wb;
|
|
|
330 SilcGaimWb wbs;
|
|
|
331
|
|
|
332 gc = client->application;
|
|
|
333 sg = gc->proto_data;
|
|
|
334
|
|
|
335 wb = gaim_whiteboard_get_session(sg->account, channel->channel_name);
|
|
|
336 if (!wb) {
|
|
|
337 /* Ask user if they want to open the whiteboard */
|
|
|
338 silcgaim_wb_request(client, message, message_len,
|
|
|
339 sender, channel);
|
|
|
340 return;
|
|
|
341 }
|
|
|
342
|
|
|
343 wbs = wb->proto_data;
|
|
|
344 silcgaim_wb_parse(wbs, wb, (unsigned char *)message, message_len);
|
|
|
345 }
|
|
|
346
|
|
|
347 /* Send whiteboard message */
|
|
|
348
|
|
|
349 void silcgaim_wb_send(GaimWhiteboard *wb, GList *draw_list)
|
|
|
350 {
|
|
|
351 SilcGaimWb wbs = wb->proto_data;
|
|
|
352 SilcBuffer packet;
|
|
|
353 GList *list;
|
|
|
354 int len;
|
|
|
355 GaimConnection *gc;
|
|
|
356 SilcGaim sg;
|
|
|
357
|
|
|
358 g_return_if_fail(draw_list);
|
|
|
359 gc = gaim_account_get_connection(wb->account);
|
|
|
360 g_return_if_fail(gc);
|
|
|
361 sg = gc->proto_data;
|
|
|
362 g_return_if_fail(sg);
|
|
|
363
|
|
|
364 len = SILCGAIM_WB_HEADER;
|
|
|
365 for (list = draw_list; list; list = list->next)
|
|
|
366 len += 4;
|
|
|
367
|
|
|
368 packet = silc_buffer_alloc_size(len);
|
|
|
369 if (!packet)
|
|
|
370 return;
|
|
|
371
|
|
|
372 /* Assmeble packet */
|
|
|
373 silc_buffer_format(packet,
|
|
|
374 SILC_STR_UI32_STRING(SILCGAIM_WB_MIME),
|
|
|
375 SILC_STR_UI_CHAR(SILCGAIM_WB_DRAW),
|
|
|
376 SILC_STR_UI_SHORT(wbs->width),
|
|
|
377 SILC_STR_UI_SHORT(wbs->height),
|
|
|
378 SILC_STR_UI_INT(wbs->brush_color),
|
|
|
379 SILC_STR_UI_SHORT(wbs->brush_size),
|
|
|
380 SILC_STR_END);
|
|
|
381 silc_buffer_pull(packet, SILCGAIM_WB_HEADER);
|
|
|
382 for (list = draw_list; list; list = list->next) {
|
|
|
383 silc_buffer_format(packet,
|
|
|
384 SILC_STR_UI_INT(GPOINTER_TO_INT(list->data)),
|
|
|
385 SILC_STR_END);
|
|
|
386 silc_buffer_pull(packet, 4);
|
|
|
387 }
|
|
|
388
|
|
|
389 /* Send the message */
|
|
|
390 if (wbs->type == 0) {
|
|
|
391 /* Private message */
|
|
|
392 silc_client_send_private_message(sg->client, sg->conn,
|
|
|
393 wbs->u.client,
|
|
|
394 SILC_MESSAGE_FLAG_DATA,
|
|
|
395 packet->head, len, TRUE);
|
|
|
396 } else if (wbs->type == 1) {
|
|
|
397 /* Channel message */
|
|
|
398 silc_client_send_channel_message(sg->client, sg->conn,
|
|
|
399 wbs->u.channel, NULL,
|
|
|
400 SILC_MESSAGE_FLAG_DATA,
|
|
|
401 packet->head, len, TRUE);
|
|
|
402 }
|
|
|
403
|
|
|
404 silc_buffer_free(packet);
|
|
|
405 }
|
|
|
406
|
|
|
407 /* Gaim Whiteboard operations */
|
|
|
408
|
|
|
409 void silcgaim_wb_start(GaimWhiteboard *wb)
|
|
|
410 {
|
|
|
411 /* Nothing here. Everything is in initialization */
|
|
|
412 }
|
|
|
413
|
|
|
414 void silcgaim_wb_end(GaimWhiteboard *wb)
|
|
|
415 {
|
|
|
416 silc_free(wb->proto_data);
|
|
|
417 wb->proto_data = NULL;
|
|
|
418 }
|
|
|
419
|
|
|
420 void silcgaim_wb_get_dimensions(GaimWhiteboard *wb, int *width, int *height)
|
|
|
421 {
|
|
|
422 SilcGaimWb wbs = wb->proto_data;
|
|
|
423 *width = wbs->width;
|
|
|
424 *height = wbs->height;
|
|
|
425 }
|
|
|
426
|
|
|
427 void silcgaim_wb_set_dimensions(GaimWhiteboard *wb, int width, int height)
|
|
|
428 {
|
|
|
429 SilcGaimWb wbs = wb->proto_data;
|
|
|
430 wbs->width = width > SILCGAIM_WB_WIDTH_MAX ? SILCGAIM_WB_WIDTH_MAX :
|
|
|
431 width;
|
|
|
432 wbs->height = height > SILCGAIM_WB_HEIGHT_MAX ? SILCGAIM_WB_HEIGHT_MAX :
|
|
|
433 height;
|
|
|
434
|
|
|
435 /* Update whiteboard */
|
|
|
436 gaim_whiteboard_set_dimensions(wb, width, height);
|
|
|
437 }
|
|
|
438
|
|
|
439 void silcgaim_wb_get_brush(GaimWhiteboard *wb, int *size, int *color)
|
|
|
440 {
|
|
|
441 SilcGaimWb wbs = wb->proto_data;
|
|
|
442 *size = wbs->brush_size;
|
|
|
443 *color = wbs->brush_color;
|
|
|
444 }
|
|
|
445
|
|
|
446 void silcgaim_wb_set_brush(GaimWhiteboard *wb, int size, int color)
|
|
|
447 {
|
|
|
448 SilcGaimWb wbs = wb->proto_data;
|
|
|
449 wbs->brush_size = size;
|
|
|
450 wbs->brush_color = color;
|
|
|
451
|
|
|
452 /* Update whiteboard */
|
|
|
453 gaim_whiteboard_set_brush(wb, size, color);
|
|
|
454 }
|
|
|
455
|
|
|
456 void silcgaim_wb_clear(GaimWhiteboard *wb)
|
|
|
457 {
|
|
|
458 SilcGaimWb wbs = wb->proto_data;
|
|
|
459 SilcBuffer packet;
|
|
|
460 int len;
|
|
|
461 GaimConnection *gc;
|
|
|
462 SilcGaim sg;
|
|
|
463
|
|
|
464 gc = gaim_account_get_connection(wb->account);
|
|
|
465 g_return_if_fail(gc);
|
|
|
466 sg = gc->proto_data;
|
|
|
467 g_return_if_fail(sg);
|
|
|
468
|
|
|
469 len = SILCGAIM_WB_HEADER;
|
|
|
470 packet = silc_buffer_alloc_size(len);
|
|
|
471 if (!packet)
|
|
|
472 return;
|
|
|
473
|
|
|
474 /* Assmeble packet */
|
|
|
475 silc_buffer_format(packet,
|
|
|
476 SILC_STR_UI32_STRING(SILCGAIM_WB_MIME),
|
|
|
477 SILC_STR_UI_CHAR(SILCGAIM_WB_CLEAR),
|
|
|
478 SILC_STR_UI_SHORT(wbs->width),
|
|
|
479 SILC_STR_UI_SHORT(wbs->height),
|
|
|
480 SILC_STR_UI_INT(wbs->brush_color),
|
|
|
481 SILC_STR_UI_SHORT(wbs->brush_size),
|
|
|
482 SILC_STR_END);
|
|
|
483
|
|
|
484 /* Send the message */
|
|
|
485 if (wbs->type == 0) {
|
|
|
486 /* Private message */
|
|
|
487 silc_client_send_private_message(sg->client, sg->conn,
|
|
|
488 wbs->u.client,
|
|
|
489 SILC_MESSAGE_FLAG_DATA,
|
|
|
490 packet->head, len, TRUE);
|
|
|
491 } else if (wbs->type == 1) {
|
|
|
492 /* Channel message */
|
|
|
493 silc_client_send_channel_message(sg->client, sg->conn,
|
|
|
494 wbs->u.channel, NULL,
|
|
|
495 SILC_MESSAGE_FLAG_DATA,
|
|
|
496 packet->head, len, TRUE);
|
|
|
497 }
|
|
|
498
|
|
|
499 silc_buffer_free(packet);
|
|
|
500 }
|