# HG changeset patch # User Ethan Blanton # Date 1131836684 0 # Node ID d5daff4609134b18e7d333678baf9b6704c0dacd # Parent 68c18dd8a316eccf36c65da9330842b276781875 [gaim-migrate @ 14353] SILC whiteboard support from Pekka Riikonen. committer: Tailor Script diff -r 68c18dd8a316 -r d5daff460913 ChangeLog --- a/ChangeLog Sat Nov 12 23:04:12 2005 +0000 +++ b/ChangeLog Sat Nov 12 23:04:44 2005 +0000 @@ -99,6 +99,7 @@ * Updated Gadu-Gadu protocol support (Bartosz Oler) * SIP/SIMPLE support (Thomas Butter) * Sametime protocol support + * SILC whiteboard support (Pekka Riikonen) Other Noteworthy Changes: * UPNP and NAT traversal support (Adam J. Warrington) diff -r 68c18dd8a316 -r d5daff460913 src/protocols/silc/buddy.c --- a/src/protocols/silc/buddy.c Sat Nov 12 23:04:12 2005 +0000 +++ b/src/protocols/silc/buddy.c Sat Nov 12 23:04:44 2005 +0000 @@ -20,6 +20,7 @@ #include "silcincludes.h" #include "silcclient.h" #include "silcgaim.h" +#include "wb.h" /***************************** Key Agreement *********************************/ @@ -1547,9 +1548,21 @@ b->name, "Killed by operator", NULL); } +typedef struct { + SilcGaim sg; + SilcClientEntry client_entry; +} *SilcGaimBuddyWb; + +static void +silcgaim_buddy_wb(GaimBlistNode *node, gpointer data) +{ + SilcGaimBuddyWb wb = data; + silcgaim_wb_init(wb->sg, wb->client_entry); + silc_free(wb); +} + GList *silcgaim_buddy_menu(GaimBuddy *buddy) { - GaimConnection *gc = gaim_account_get_connection(buddy->account); SilcGaim sg = gc->proto_data; SilcClientConnection conn = sg->conn; @@ -1557,6 +1570,7 @@ SilcClientEntry client_entry = NULL; GaimBlistNodeAction *act; GList *m = NULL; + SilcGaimBuddyWb wb; pkfile = gaim_blist_node_get_string((GaimBlistNode *) buddy, "public-key"); client_entry = silc_client_get_client_by_id(sg->client, @@ -1597,5 +1611,12 @@ m = g_list_append(m, act); } + wb = silc_calloc(1, sizeof(*wb)); + wb->sg = sg; + wb->client_entry = client_entry; + act = gaim_blist_node_action_new(_("Draw On Whiteboard"), + silcgaim_buddy_wb, (void *)wb, NULL); + m = g_list_append(m, act); + return m; } diff -r 68c18dd8a316 -r d5daff460913 src/protocols/silc/chat.c --- a/src/protocols/silc/chat.c Sat Nov 12 23:04:12 2005 +0000 +++ b/src/protocols/silc/chat.c Sat Nov 12 23:04:44 2005 +0000 @@ -20,6 +20,7 @@ #include "silcincludes.h" #include "silcclient.h" #include "silcgaim.h" +#include "wb.h" /***************************** Channel Routines ******************************/ @@ -832,6 +833,19 @@ "+s", NULL); } +typedef struct { + SilcGaim sg; + SilcChannelEntry channel; +} *SilcGaimChatWb; + +static void +silcgaim_chat_wb(GaimBlistNode *node, gpointer data) +{ + SilcGaimChatWb wb = data; + silcgaim_wb_init_ch(wb->sg, wb->channel); + silc_free(wb); +} + GList *silcgaim_chat_menu(GaimChat *chat) { GHashTable *components = chat->components; @@ -949,6 +963,16 @@ } } + if (channel) { + SilcGaimChatWb wb; + wb = silc_calloc(1, sizeof(*wb)); + wb->sg = sg; + wb->channel = channel; + act = gaim_blist_node_action_new(_("Draw On Whiteboard"), + silcgaim_chat_wb, (void *)wb, NULL); + m = g_list_append(m, act); + } + return m; } diff -r 68c18dd8a316 -r d5daff460913 src/protocols/silc/ops.c --- a/src/protocols/silc/ops.c Sat Nov 12 23:04:12 2005 +0000 +++ b/src/protocols/silc/ops.c Sat Nov 12 23:04:44 2005 +0000 @@ -20,6 +20,7 @@ #include "silcincludes.h" #include "silcclient.h" #include "silcgaim.h" +#include "wb.h" /* Message sent to the application by library. `conn' associates the message to a specific connection. `conn', however, may be NULL. @@ -80,7 +81,23 @@ } if (flags & SILC_MESSAGE_FLAG_DATA) { - /* XXX */ + char type[128], enc[128]; + unsigned char *data; + SilcUInt32 data_len; + + memset(type, 0, sizeof(type)); + memset(enc, 0, sizeof(enc)); + + if (!silc_mime_parse(message, message_len, NULL, 0, + type, sizeof(type) - 1, enc, sizeof(enc) - 1, &data, + &data_len)) + return; + + if (!strcmp(type, "application/x-wb") && + !strcmp(enc, "binary")) + silcgaim_wb_receive_ch(client, conn, sender, channel, + payload, flags, data, data_len); + return; } @@ -159,7 +176,23 @@ } if (flags & SILC_MESSAGE_FLAG_DATA) { - /* XXX */ + char type[128], enc[128]; + unsigned char *data; + SilcUInt32 data_len; + + memset(type, 0, sizeof(type)); + memset(enc, 0, sizeof(enc)); + + if (!silc_mime_parse(message, message_len, NULL, 0, + type, sizeof(type) - 1, enc, sizeof(enc) - 1, &data, + &data_len)) + return; + + if (!strcmp(type, "application/x-wb") && + !strcmp(enc, "binary")) + silcgaim_wb_receive(client, conn, sender, payload, + flags, data, data_len); + return; } diff -r 68c18dd8a316 -r d5daff460913 src/protocols/silc/silc.c --- a/src/protocols/silc/silc.c Sat Nov 12 23:04:12 2005 +0000 +++ b/src/protocols/silc/silc.c Sat Nov 12 23:04:44 2005 +0000 @@ -21,6 +21,7 @@ #include "silcclient.h" #include "silcgaim.h" #include "version.h" +#include "wb.h" extern SilcClientOperations ops; static GaimPlugin *silc_plugin = NULL; @@ -1484,6 +1485,18 @@ silcgaim_pref_frame, }; +static GaimWhiteboardPrplOps silcgaim_wb_ops = +{ + silcgaim_wb_start, + silcgaim_wb_end, + silcgaim_wb_get_dimensions, + silcgaim_wb_set_dimensions, + silcgaim_wb_get_brush, + silcgaim_wb_set_brush, + silcgaim_wb_send, + silcgaim_wb_clear, +}; + static GaimPluginProtocolInfo prpl_info = { OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | @@ -1543,7 +1556,8 @@ silcgaim_roomlist_cancel, /* roomlist_cancel */ NULL, /* roomlist_expand_category */ NULL, /* can_receive_file */ - silcgaim_ftp_send_file /* send_file */ + silcgaim_ftp_send_file, /* send_file */ + &silcgaim_wb_ops, /* whiteboard operations */ }; static GaimPluginInfo info = diff -r 68c18dd8a316 -r d5daff460913 src/protocols/silc/wb.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/silc/wb.c Sat Nov 12 23:04:44 2005 +0000 @@ -0,0 +1,500 @@ +/* + + wb.c + + Author: Pekka Riikonen + + Copyright (C) 2005 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#include "silcincludes.h" +#include "silcclient.h" +#include "silcgaim.h" +#include "wb.h" + +/* + SILC Whiteboard packet: + + 1 byte command + 2 bytes width + 2 bytes height + 4 bytes brush color + 2 bytes brush size + n bytes data + + Data: + + 4 bytes x + 4 bytes y + + Commands: + + 0x01 draw + 0x02 clear + + MIME: + + MIME-Version: 1.0 + Content-Type: application/x-wb + Content-Transfer-Encoding: binary + +*/ + +#define SILCGAIM_WB_MIME "MIME-Version: 1.0\r\nContent-Type: application/x-wb\r\nContent-Transfer-Encoding: binary\r\n\r\n" +#define SILCGAIM_WB_HEADER strlen(SILCGAIM_WB_MIME) + 11 + +#define SILCGAIM_WB_WIDTH 500 +#define SILCGAIM_WB_HEIGHT 400 +#define SILCGAIM_WB_WIDTH_MAX 1024 +#define SILCGAIM_WB_HEIGHT_MAX 1024 + +/* Commands */ +typedef enum { + SILCGAIM_WB_DRAW = 0x01, + SILCGAIM_WB_CLEAR = 0x02, +} SilcGaimWbCommand; + +/* Brush size */ +typedef enum { + SILCGAIM_WB_BRUSH_SMALL = 2, + SILCGAIM_WB_BRUSH_MEDIUM = 5, + SILCGAIM_WB_BRUSH_LARGE = 10, +} SilcGaimWbBrushSize; + +/* Brush color (XXX Gaim should provide default colors) */ +typedef enum { + SILCGAIM_WB_COLOR_BLACK = 0, + SILCGAIM_WB_COLOR_RED = 13369344, + SILCGAIM_WB_COLOR_GREEN = 52224, + SILCGAIM_WB_COLOR_BLUE = 204, + SILCGAIM_WB_COLOR_YELLOW = 15658496, + SILCGAIM_WB_COLOR_ORANGE = 16737792, + SILCGAIM_WB_COLOR_CYAN = 52428, + SILCGAIM_WB_COLOR_VIOLET = 5381277, + SILCGAIM_WB_COLOR_PURPLE = 13369548, + SILCGAIM_WB_COLOR_TAN = 12093547, + SILCGAIM_WB_COLOR_BROWN = 5256485, + SILCGAIM_WB_COLOR_GREY = 11184810, + SILCGAIM_WB_COLOR_WHITE = 16777215, +} SilcGaimWbColor; + +typedef struct { + int type; /* 0 = buddy, 1 = channel */ + union { + SilcClientEntry client; + SilcChannelEntry channel; + } u; + int width; + int height; + int brush_size; + int brush_color; +} *SilcGaimWb; + +/* Initialize whiteboard */ + +GaimWhiteboard *silcgaim_wb_init(SilcGaim sg, SilcClientEntry client_entry) +{ + SilcClientConnection conn; + GaimWhiteboard *wb; + SilcGaimWb wbs; + + conn = sg->conn; + wb = gaim_whiteboard_get_session(sg->account, client_entry->nickname); + if (!wb) + wb = gaim_whiteboard_create(sg->account, client_entry->nickname, + 0); + if (!wb) + return NULL; + + wbs = silc_calloc(1, sizeof(*wbs)); + if (!wbs) + return NULL; + wbs->type = 0; + wbs->u.client = client_entry; + wbs->width = SILCGAIM_WB_WIDTH; + wbs->height = SILCGAIM_WB_HEIGHT; + wbs->brush_size = SILCGAIM_WB_BRUSH_SMALL; + wbs->brush_color = SILCGAIM_WB_COLOR_BLACK; + wb->proto_data = wbs; + + /* Start the whiteboard */ + gaim_whiteboard_start(wb); + gaim_whiteboard_clear(wb); + + return wb; +} + +GaimWhiteboard *silcgaim_wb_init_ch(SilcGaim sg, SilcChannelEntry channel) +{ + GaimWhiteboard *wb; + SilcGaimWb wbs; + + wb = gaim_whiteboard_get_session(sg->account, channel->channel_name); + if (!wb) + wb = gaim_whiteboard_create(sg->account, channel->channel_name, + 0); + if (!wb) + return NULL; + + wbs = silc_calloc(1, sizeof(*wbs)); + if (!wbs) + return NULL; + wbs->type = 1; + wbs->u.channel = channel; + wbs->width = SILCGAIM_WB_WIDTH; + wbs->height = SILCGAIM_WB_HEIGHT; + wbs->brush_size = SILCGAIM_WB_BRUSH_SMALL; + wbs->brush_color = SILCGAIM_WB_COLOR_BLACK; + wb->proto_data = wbs; + + /* Start the whiteboard */ + gaim_whiteboard_start(wb); + gaim_whiteboard_clear(wb); + + return wb; +} + +static void +silcgaim_wb_parse(SilcGaimWb wbs, GaimWhiteboard *wb, + unsigned char *message, SilcUInt32 message_len) +{ + SilcUInt8 command; + SilcUInt16 width, height, brush_size; + SilcUInt32 brush_color, x, y, dx, dy; + SilcBufferStruct buf; + int ret; + + /* Parse the packet */ + silc_buffer_set(&buf, message, message_len); + ret = silc_buffer_unformat(&buf, + SILC_STR_UI_CHAR(&command), + SILC_STR_UI_SHORT(&width), + SILC_STR_UI_SHORT(&height), + SILC_STR_UI_INT(&brush_color), + SILC_STR_UI_SHORT(&brush_size), + SILC_STR_END); + if (ret < 0) + return; + silc_buffer_pull(&buf, ret); + + /* Update whiteboard if its dimensions changed */ + if (width != wbs->width || height != wbs->height) + silcgaim_wb_set_dimensions(wb, height, width); + + if (command == SILCGAIM_WB_DRAW) { + /* Parse data and draw it */ + ret = silc_buffer_unformat(&buf, + SILC_STR_UI_INT(&dx), + SILC_STR_UI_INT(&dy), + SILC_STR_END); + if (ret < 0) + return; + silc_buffer_pull(&buf, 8); + x = dx; + y = dy; + while (buf.len > 0) { + ret = silc_buffer_unformat(&buf, + SILC_STR_UI_INT(&dx), + SILC_STR_UI_INT(&dy), + SILC_STR_END); + if (ret < 0) + return; + silc_buffer_pull(&buf, 8); + + gaim_whiteboard_draw_line(wb, x, y, x + dx, y + dy, + brush_color, brush_size); + x += dx; + y += dy; + } + } + + if (command == SILCGAIM_WB_CLEAR) + gaim_whiteboard_clear(wb); +} + +typedef struct { + unsigned char *message; + SilcUInt32 message_len; + SilcGaim sg; + SilcClientEntry sender; + SilcChannelEntry channel; +} *SilcGaimWbRequest; + +static void +silcgaim_wb_request_cb(SilcGaimWbRequest req, gint id) +{ + GaimWhiteboard *wb; + + if (id != 1) + goto out; + + if (!req->channel) + wb = silcgaim_wb_init(req->sg, req->sender); + else + wb = silcgaim_wb_init_ch(req->sg, req->channel); + + silcgaim_wb_parse(wb->proto_data, wb, req->message, req->message_len); + + out: + silc_free(req->message); + silc_free(req); +} + +static void +silcgaim_wb_request(SilcClient client, const unsigned char *message, + SilcUInt32 message_len, SilcClientEntry sender, + SilcChannelEntry channel) +{ + char tmp[128]; + SilcGaimWbRequest req; + GaimConnection *gc; + SilcGaim sg; + + if (!channel) { + g_snprintf(tmp, sizeof(tmp), + _("%s sent message to whiteboard. Would you like " + "to open the whiteboard?"), sender->nickname); + } else { + g_snprintf(tmp, sizeof(tmp), + _("%s sent message to whiteboard on %s channel. " + "Would you like to open the whiteboard?"), + sender->nickname, channel->channel_name); + } + + gc = client->application; + sg = gc->proto_data; + + req = silc_calloc(1, sizeof(*req)); + if (!req) + return; + req->message = silc_memdup(message, message_len); + req->message_len = message_len; + req->sender = sender; + req->channel = channel; + req->sg = sg; + + gaim_request_action(gc, _("Whiteboard"), tmp, NULL, 1, req, 2, + _("Yes"), G_CALLBACK(silcgaim_wb_request_cb), + _("No"), G_CALLBACK(silcgaim_wb_request_cb)); +} + +/* Process incoming whiteboard message */ + +void silcgaim_wb_receive(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcMessagePayload payload, + SilcMessageFlags flags, const unsigned char *message, + SilcUInt32 message_len) +{ + SilcGaim sg; + GaimConnection *gc; + GaimWhiteboard *wb; + SilcGaimWb wbs; + + gc = client->application; + sg = gc->proto_data; + + wb = gaim_whiteboard_get_session(sg->account, sender->nickname); + if (!wb) { + /* Ask user if they want to open the whiteboard */ + silcgaim_wb_request(client, message, message_len, + sender, NULL); + return; + } + + wbs = wb->proto_data; + silcgaim_wb_parse(wbs, wb, (unsigned char *)message, message_len); +} + +/* Process incoming whiteboard message on channel */ + +void silcgaim_wb_receive_ch(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcChannelEntry channel, + SilcMessagePayload payload, + SilcMessageFlags flags, + const unsigned char *message, + SilcUInt32 message_len) +{ + SilcGaim sg; + GaimConnection *gc; + GaimWhiteboard *wb; + SilcGaimWb wbs; + + gc = client->application; + sg = gc->proto_data; + + wb = gaim_whiteboard_get_session(sg->account, channel->channel_name); + if (!wb) { + /* Ask user if they want to open the whiteboard */ + silcgaim_wb_request(client, message, message_len, + sender, channel); + return; + } + + wbs = wb->proto_data; + silcgaim_wb_parse(wbs, wb, (unsigned char *)message, message_len); +} + +/* Send whiteboard message */ + +void silcgaim_wb_send(GaimWhiteboard *wb, GList *draw_list) +{ + SilcGaimWb wbs = wb->proto_data; + SilcBuffer packet; + GList *list; + int len; + GaimConnection *gc; + SilcGaim sg; + + g_return_if_fail(draw_list); + gc = gaim_account_get_connection(wb->account); + g_return_if_fail(gc); + sg = gc->proto_data; + g_return_if_fail(sg); + + len = SILCGAIM_WB_HEADER; + for (list = draw_list; list; list = list->next) + len += 4; + + packet = silc_buffer_alloc_size(len); + if (!packet) + return; + + /* Assmeble packet */ + silc_buffer_format(packet, + SILC_STR_UI32_STRING(SILCGAIM_WB_MIME), + SILC_STR_UI_CHAR(SILCGAIM_WB_DRAW), + SILC_STR_UI_SHORT(wbs->width), + SILC_STR_UI_SHORT(wbs->height), + SILC_STR_UI_INT(wbs->brush_color), + SILC_STR_UI_SHORT(wbs->brush_size), + SILC_STR_END); + silc_buffer_pull(packet, SILCGAIM_WB_HEADER); + for (list = draw_list; list; list = list->next) { + silc_buffer_format(packet, + SILC_STR_UI_INT(GPOINTER_TO_INT(list->data)), + SILC_STR_END); + silc_buffer_pull(packet, 4); + } + + /* Send the message */ + if (wbs->type == 0) { + /* Private message */ + silc_client_send_private_message(sg->client, sg->conn, + wbs->u.client, + SILC_MESSAGE_FLAG_DATA, + packet->head, len, TRUE); + } else if (wbs->type == 1) { + /* Channel message */ + silc_client_send_channel_message(sg->client, sg->conn, + wbs->u.channel, NULL, + SILC_MESSAGE_FLAG_DATA, + packet->head, len, TRUE); + } + + silc_buffer_free(packet); +} + +/* Gaim Whiteboard operations */ + +void silcgaim_wb_start(GaimWhiteboard *wb) +{ + /* Nothing here. Everything is in initialization */ +} + +void silcgaim_wb_end(GaimWhiteboard *wb) +{ + silc_free(wb->proto_data); + wb->proto_data = NULL; +} + +void silcgaim_wb_get_dimensions(GaimWhiteboard *wb, int *width, int *height) +{ + SilcGaimWb wbs = wb->proto_data; + *width = wbs->width; + *height = wbs->height; +} + +void silcgaim_wb_set_dimensions(GaimWhiteboard *wb, int width, int height) +{ + SilcGaimWb wbs = wb->proto_data; + wbs->width = width > SILCGAIM_WB_WIDTH_MAX ? SILCGAIM_WB_WIDTH_MAX : + width; + wbs->height = height > SILCGAIM_WB_HEIGHT_MAX ? SILCGAIM_WB_HEIGHT_MAX : + height; + + /* Update whiteboard */ + gaim_whiteboard_set_dimensions(wb, width, height); +} + +void silcgaim_wb_get_brush(GaimWhiteboard *wb, int *size, int *color) +{ + SilcGaimWb wbs = wb->proto_data; + *size = wbs->brush_size; + *color = wbs->brush_color; +} + +void silcgaim_wb_set_brush(GaimWhiteboard *wb, int size, int color) +{ + SilcGaimWb wbs = wb->proto_data; + wbs->brush_size = size; + wbs->brush_color = color; + + /* Update whiteboard */ + gaim_whiteboard_set_brush(wb, size, color); +} + +void silcgaim_wb_clear(GaimWhiteboard *wb) +{ + SilcGaimWb wbs = wb->proto_data; + SilcBuffer packet; + int len; + GaimConnection *gc; + SilcGaim sg; + + gc = gaim_account_get_connection(wb->account); + g_return_if_fail(gc); + sg = gc->proto_data; + g_return_if_fail(sg); + + len = SILCGAIM_WB_HEADER; + packet = silc_buffer_alloc_size(len); + if (!packet) + return; + + /* Assmeble packet */ + silc_buffer_format(packet, + SILC_STR_UI32_STRING(SILCGAIM_WB_MIME), + SILC_STR_UI_CHAR(SILCGAIM_WB_CLEAR), + SILC_STR_UI_SHORT(wbs->width), + SILC_STR_UI_SHORT(wbs->height), + SILC_STR_UI_INT(wbs->brush_color), + SILC_STR_UI_SHORT(wbs->brush_size), + SILC_STR_END); + + /* Send the message */ + if (wbs->type == 0) { + /* Private message */ + silc_client_send_private_message(sg->client, sg->conn, + wbs->u.client, + SILC_MESSAGE_FLAG_DATA, + packet->head, len, TRUE); + } else if (wbs->type == 1) { + /* Channel message */ + silc_client_send_channel_message(sg->client, sg->conn, + wbs->u.channel, NULL, + SILC_MESSAGE_FLAG_DATA, + packet->head, len, TRUE); + } + + silc_buffer_free(packet); +} diff -r 68c18dd8a316 -r d5daff460913 src/protocols/silc/wb.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/silc/wb.h Sat Nov 12 23:04:44 2005 +0000 @@ -0,0 +1,49 @@ +/* + + silcgaim.h + + Author: Pekka Riikonen + + Copyright (C) 2005 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef SILCGAIM_WB_H +#define SILCGAIM_WB_H + +#include "silcgaim.h" +#include "whiteboard.h" + +GaimWhiteboard * +silcgaim_wb_init(SilcGaim sg, SilcClientEntry client_entry); +GaimWhiteboard * +silcgaim_wb_init_ch(SilcGaim sg, SilcChannelEntry channel); +void silcgaim_wb_receive(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcMessagePayload payload, + SilcMessageFlags flags, const unsigned char *message, + SilcUInt32 message_len); +void silcgaim_wb_receive_ch(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcChannelEntry channel, + SilcMessagePayload payload, + SilcMessageFlags flags, + const unsigned char *message, + SilcUInt32 message_len); +void silcgaim_wb_start(GaimWhiteboard *wb); +void silcgaim_wb_end(GaimWhiteboard *wb); +void silcgaim_wb_get_dimensions(GaimWhiteboard *wb, int *width, int *height); +void silcgaim_wb_set_dimensions(GaimWhiteboard *wb, int width, int height); +void silcgaim_wb_get_brush(GaimWhiteboard *wb, int *size, int *color); +void silcgaim_wb_set_brush(GaimWhiteboard *wb, int size, int color); +void silcgaim_wb_send(GaimWhiteboard *wb, GList *draw_list); +void silcgaim_wb_clear(GaimWhiteboard *wb); + +#endif /* SILCGAIM_WB_H */