| 1 #include <stdio.h> |
|
| 2 #include <assert.h> |
|
| 3 |
|
| 4 #include "internal.h" |
|
| 5 #include "plugin.h" |
|
| 6 #include "gtkplugin.h" |
|
| 7 #include "gtkblist.h" |
|
| 8 #include "gtkutils.h" |
|
| 9 #include "connection.h" |
|
| 10 #include "conversation.h" |
|
| 11 #include "network.h" |
|
| 12 |
|
| 13 #include <gtk/gtkgl.h> |
|
| 14 #include <GL/gl.h> |
|
| 15 #include <GL/glu.h> |
|
| 16 |
|
| 17 #include "crazychat.h" |
|
| 18 #include "cc_network.h" |
|
| 19 #include "cc_interface.h" |
|
| 20 #include "cc_gtk_gl.h" |
|
| 21 #include "util.h" |
|
| 22 |
|
| 23 /* --- begin type and global variable definitions --- */ |
|
| 24 |
|
| 25 static struct crazychat cc_info; |
|
| 26 |
|
| 27 /* --- begin function declarations --- */ |
|
| 28 |
|
| 29 /** |
|
| 30 * Called by gaim plugin to start CrazyChat |
|
| 31 * @param cc the crazychat struct |
|
| 32 */ |
|
| 33 static void cc_init(struct crazychat *cc); |
|
| 34 |
|
| 35 /** |
|
| 36 * Called by gaim plugin to destroy CrazyChat |
|
| 37 * @param cc the crazychat struct |
|
| 38 */ |
|
| 39 static void cc_destroy(struct crazychat *cc); |
|
| 40 |
|
| 41 |
|
| 42 /** |
|
| 43 * Buddy menu drawing callback. Adds a CrazyChat menuitem. |
|
| 44 * @param menu the buddy menu widget |
|
| 45 * @param b the buddy whose menu this is |
|
| 46 */ |
|
| 47 static gboolean cc_buddy_menu(GtkWidget *menu, GaimBuddy *b); |
|
| 48 |
|
| 49 /** |
|
| 50 * Buddy menu callback. Initiates the CrazyChat session. |
|
| 51 * @param item the gtk buddy menu item |
|
| 52 * @param b the buddy whose menu the item was in |
|
| 53 */ |
|
| 54 static void cc_menu_cb(GtkMenuItem *item, GaimBuddy *b); |
|
| 55 |
|
| 56 /** |
|
| 57 * IM callback. Handles receiving a CrazyChat session request. |
|
| 58 * @param account the account we received the IM on |
|
| 59 * @param sender the buddy who we received the message from |
|
| 60 * @param message the message we received |
|
| 61 * @param flags IM flags |
|
| 62 * @param data user data |
|
| 63 */ |
|
| 64 static gboolean receive_im_cb(GaimAccount *account, char **sender, |
|
| 65 char **message, int *flags, void *data); |
|
| 66 |
|
| 67 /** |
|
| 68 * Displaying IM callback. Drops CrazyChat messages from IM window. |
|
| 69 * @param account the account we are displaying the IM on |
|
| 70 * @param conv the conversation we are displaying the IM on |
|
| 71 * @param message the message we are displaying |
|
| 72 * @param data user data |
|
| 73 */ |
|
| 74 static gboolean display_im_cb(GaimAccount *account, const char *who, char **message, |
|
| 75 GaimConnection *conv, GaimMessageFlags flags, void *data); |
|
| 76 |
|
| 77 /** |
|
| 78 * Callback for CrazyChat plugin configuration frame |
|
| 79 * @param plugin the plugin data |
|
| 80 * @return the configuration frame |
|
| 81 */ |
|
| 82 static GtkWidget *get_config_frame(GaimPlugin *plugin); |
|
| 83 |
|
| 84 /** |
|
| 85 * TCP port callback. Changes the port used to listen for new CC sessions |
|
| 86 * @param spin the spinner button whose value changed |
|
| 87 * @param data user data |
|
| 88 */ |
|
| 89 static void tcp_port_cb(GtkSpinButton *spin, struct crazychat *cc); |
|
| 90 |
|
| 91 /** |
|
| 92 * UDP port callback. Changes the port used to send/recv CC session frames |
|
| 93 * @param spin the spinner button whose value changed |
|
| 94 * @param data user data |
|
| 95 */ |
|
| 96 static void udp_port_cb(GtkSpinButton *spin, struct crazychat *cc); |
|
| 97 |
|
| 98 /** |
|
| 99 * Features enabling/disabling callback. Initializes the input processing |
|
| 100 * or shuts it down. |
|
| 101 * @param data user data |
|
| 102 */ |
|
| 103 static void features_enable_cb(struct crazychat *cc); |
|
| 104 |
|
| 105 /** |
|
| 106 * User signed on callback. Now we have a buddy list to connect a signal |
|
| 107 * handler to. |
|
| 108 * @param gc the gaim connection we are signed on |
|
| 109 * @param plugin our plugin struct |
|
| 110 */ |
|
| 111 static gboolean cc_signed_on(GaimConnection *gc, void *plugin); |
|
| 112 |
|
| 113 /** |
|
| 114 * Plugin loading callback. If a buddy list exists, connect our buddy menu |
|
| 115 * drawing callback to the signal handler, otherwise, connect a signed on |
|
| 116 * signal handler so we know when we get a buddy list. |
|
| 117 * @param plugin our plugin struct |
|
| 118 */ |
|
| 119 static gboolean plugin_load(GaimPlugin *plugin); |
|
| 120 |
|
| 121 /** |
|
| 122 * Plugin unloading callback. Disconnect all handlers and free data. |
|
| 123 * @param plugin our plugin struct |
|
| 124 */ |
|
| 125 static gboolean plugin_unload(GaimPlugin *plugin); |
|
| 126 |
|
| 127 |
|
| 128 /* --- end function declarations --- */ |
|
| 129 |
|
| 130 |
|
| 131 #define CRAZYCHAT_PLUGIN_ID "gtk-crazychat" |
|
| 132 |
|
| 133 static GaimGtkPluginUiInfo ui_info = { |
|
| 134 get_config_frame /**< get_config_frame */ |
|
| 135 }; |
|
| 136 |
|
| 137 static GaimPluginInfo info = { |
|
| 138 2, /**< api_version */ |
|
| 139 GAIM_PLUGIN_STANDARD, /**< type */ |
|
| 140 GAIM_GTK_PLUGIN_TYPE, /**< ui_requirement */ |
|
| 141 0, /**< flags */ |
|
| 142 NULL, /**< dependencies */ |
|
| 143 GAIM_PRIORITY_DEFAULT, /**< priority */ |
|
| 144 |
|
| 145 CRAZYCHAT_PLUGIN_ID, /**< id */ |
|
| 146 N_("Crazychat"), /**< name */ |
|
| 147 VERSION, /**< version */ |
|
| 148 /** summary */ |
|
| 149 N_("Plugin to establish a Crazychat session."), |
|
| 150 /** description */ |
|
| 151 N_("Uses Gaim to obtain buddy ips to connect for a Crazychat session"), |
|
| 152 "\n" |
|
| 153 "William Chan <chanman@stanford.edu>\n" |
|
| 154 "Ian Spiro <ispiro@stanford.edu>\n" |
|
| 155 "Charlie Stockman<stockman@stanford.edu>\n" |
|
| 156 "Steve Yelderman<scy@stanford.edu>", /**< author */ |
|
| 157 GAIM_WEBSITE, /**< homepage */ |
|
| 158 |
|
| 159 plugin_load, /**< load */ |
|
| 160 plugin_unload, /**< unload */ |
|
| 161 NULL, /**< destroy */ |
|
| 162 |
|
| 163 &ui_info, /**< ui_info */ |
|
| 164 &cc_info /**< extra_info */ |
|
| 165 }; |
|
| 166 |
|
| 167 /* --- end plugin struct definition --- */ |
|
| 168 |
|
| 169 static void cc_init(struct crazychat *cc) |
|
| 170 { |
|
| 171 /* initialize main crazychat thread */ |
|
| 172 |
|
| 173 assert(cc); |
|
| 174 memset(cc, 0, sizeof(*cc)); |
|
| 175 |
|
| 176 /* initialize network configuration */ |
|
| 177 cc->tcp_port = DEFAULT_CC_PORT; |
|
| 178 cc->udp_port = DEFAULT_CC_PORT; |
|
| 179 |
|
| 180 /* disable input subsystem */ |
|
| 181 //cc->features_state = 0; |
|
| 182 |
|
| 183 /* initialize input subsystem */ |
|
| 184 cc->features_state = 1; |
|
| 185 cc->input_data = init_input(cc); |
|
| 186 } |
|
| 187 |
|
| 188 static void cc_destroy(struct crazychat *cc) |
|
| 189 { |
|
| 190 assert(cc); |
|
| 191 |
|
| 192 if (cc->features_state) { |
|
| 193 destroy_input(cc->input_data); |
|
| 194 } |
|
| 195 memset(cc, 0, sizeof(*cc)); |
|
| 196 } |
|
| 197 |
|
| 198 static gboolean cc_buddy_menu(GtkWidget *menu, GaimBuddy *b) |
|
| 199 { |
|
| 200 GtkWidget *menuitem; |
|
| 201 |
|
| 202 menuitem = gtk_menu_item_new_with_mnemonic("CrazyChat"); |
|
| 203 g_signal_connect(G_OBJECT(menuitem), "activate", |
|
| 204 G_CALLBACK(cc_menu_cb), b); |
|
| 205 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); |
|
| 206 return FALSE; |
|
| 207 } |
|
| 208 |
|
| 209 static void cc_menu_cb(GtkMenuItem *item, GaimBuddy *b) |
|
| 210 { |
|
| 211 assert(item); |
|
| 212 assert(b); |
|
| 213 |
|
| 214 /* send the invite */ |
|
| 215 cc_net_send_invite(&cc_info, b->name, b->account); |
|
| 216 } |
|
| 217 |
|
| 218 static gboolean receive_im_cb(GaimAccount *account, char **sender, |
|
| 219 char **message, int *flags, void *data) |
|
| 220 { |
|
| 221 struct crazychat *cc; |
|
| 222 |
|
| 223 cc = (struct crazychat*)data; |
|
| 224 assert(cc); |
|
| 225 if (!strncmp(*message, CRAZYCHAT_INVITE_CODE, |
|
| 226 strlen(CRAZYCHAT_INVITE_CODE))) { |
|
| 227 Debug(*message); |
|
| 228 char *split = strchr(*message, '!'); |
|
| 229 assert(split); |
|
| 230 *split = 0; |
|
| 231 split++; |
|
| 232 cc_net_recv_invite(account, cc, *sender, |
|
| 233 &(*message)[strlen(CRAZYCHAT_INVITE_CODE)], |
|
| 234 split); |
|
| 235 return TRUE; |
|
| 236 } else if (!strncmp(*message, CRAZYCHAT_ACCEPT_CODE, |
|
| 237 strlen(CRAZYCHAT_ACCEPT_CODE))) { |
|
| 238 cc_net_recv_accept(account, cc, *sender, |
|
| 239 &(*message)[strlen(CRAZYCHAT_ACCEPT_CODE)]); |
|
| 240 return TRUE; |
|
| 241 } else if (!strncmp(*message, CRAZYCHAT_READY_CODE, |
|
| 242 strlen(CRAZYCHAT_READY_CODE))) { |
|
| 243 cc_net_recv_ready(account, cc, *sender); |
|
| 244 return TRUE; |
|
| 245 } |
|
| 246 |
|
| 247 return FALSE; |
|
| 248 } |
|
| 249 |
|
| 250 static gboolean display_im_cb(GaimAccount *account, GaimConversation *conv, |
|
| 251 char **message, void *data) |
|
| 252 { |
|
| 253 struct crazychat *cc; |
|
| 254 |
|
| 255 cc = (struct crazychat*)data; |
|
| 256 assert(cc); |
|
| 257 if (!strncmp(*message, CRAZYCHAT_INVITE_CODE, |
|
| 258 strlen(CRAZYCHAT_INVITE_CODE))) { |
|
| 259 return TRUE; |
|
| 260 } else if (!strncmp(*message, CRAZYCHAT_ACCEPT_CODE, |
|
| 261 strlen(CRAZYCHAT_ACCEPT_CODE))) { |
|
| 262 return TRUE; |
|
| 263 } else if (!strncmp(*message, CRAZYCHAT_READY_CODE, |
|
| 264 strlen(CRAZYCHAT_READY_CODE))) { |
|
| 265 return TRUE; |
|
| 266 } |
|
| 267 |
|
| 268 return FALSE; |
|
| 269 } |
|
| 270 |
|
| 271 static GtkWidget *get_config_frame(GaimPlugin *plugin) |
|
| 272 { |
|
| 273 GtkWidget *ret; |
|
| 274 GtkWidget *frame; |
|
| 275 GtkWidget *vbox, *hbox; |
|
| 276 GtkWidget *drawing_area; |
|
| 277 GtkWidget *label; |
|
| 278 GtkAdjustment *adj; |
|
| 279 GtkWidget *spinner; |
|
| 280 GtkWidget *button, *button1, *button2; |
|
| 281 GSList *group; |
|
| 282 struct draw_info *info; |
|
| 283 struct crazychat *cc; |
|
| 284 |
|
| 285 cc = (struct crazychat*)plugin->info->extra_info; |
|
| 286 assert(cc); |
|
| 287 |
|
| 288 /* create widgets */ |
|
| 289 |
|
| 290 /* creating the config frame */ |
|
| 291 ret = gtk_vbox_new(FALSE, 18); |
|
| 292 gtk_container_set_border_width(GTK_CONTAINER(ret), 12); |
|
| 293 |
|
| 294 /* make the network configuration frame */ |
|
| 295 frame = gaim_gtk_make_frame(ret, _("Network Configuration")); |
|
| 296 gtk_widget_show(frame); |
|
| 297 |
|
| 298 /* add boxes for packing purposes */ |
|
| 299 vbox = gtk_vbox_new(FALSE, 0); |
|
| 300 gtk_box_pack_start(GTK_BOX(frame), vbox, TRUE, TRUE, 0); |
|
| 301 gtk_widget_show(vbox); |
|
| 302 |
|
| 303 /* add widgets to row 1 */ |
|
| 304 hbox = gtk_hbox_new(FALSE, 0); |
|
| 305 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); |
|
| 306 gtk_widget_show(hbox); |
|
| 307 label = gtk_label_new(_("TCP port")); |
|
| 308 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 15); |
|
| 309 gtk_widget_show(label); |
|
| 310 adj = (GtkAdjustment*)gtk_adjustment_new(DEFAULT_CC_PORT, 1, |
|
| 311 G_MAXUSHORT, 1, 1000, 0); |
|
| 312 spinner = gtk_spin_button_new(adj, 1, 0); |
|
| 313 g_signal_connect(G_OBJECT(spinner), "value_changed", |
|
| 314 G_CALLBACK(tcp_port_cb), cc); |
|
| 315 gtk_box_pack_start(GTK_BOX(hbox), spinner, FALSE, FALSE, 0); |
|
| 316 gtk_widget_show(spinner); |
|
| 317 label = gtk_label_new(_("UDP port")); |
|
| 318 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 15); |
|
| 319 gtk_widget_show(label); |
|
| 320 adj = (GtkAdjustment*)gtk_adjustment_new(DEFAULT_CC_PORT, 1, |
|
| 321 G_MAXUSHORT, 1, 1000, 0); |
|
| 322 spinner = gtk_spin_button_new(adj, 1, 0); |
|
| 323 g_signal_connect(G_OBJECT(spinner), "value_changed", |
|
| 324 G_CALLBACK(udp_port_cb), cc); |
|
| 325 gtk_box_pack_start(GTK_BOX(hbox), spinner, FALSE, FALSE, 0); |
|
| 326 gtk_widget_show(spinner); |
|
| 327 |
|
| 328 /* make the feature configuration frame */ |
|
| 329 frame = gaim_gtk_make_frame(ret, _("Feature Calibration")); |
|
| 330 gtk_widget_show(frame); |
|
| 331 |
|
| 332 /* add hbox for packing purposes */ |
|
| 333 hbox = gtk_hbox_new(TRUE, 40); |
|
| 334 gtk_box_pack_start(GTK_BOX(frame), hbox, TRUE, TRUE, 0); |
|
| 335 gtk_widget_show(hbox); |
|
| 336 |
|
| 337 /* add feature calibration options */ |
|
| 338 |
|
| 339 /* add vbox for packing purposes */ |
|
| 340 vbox = gtk_vbox_new(TRUE, 0); |
|
| 341 gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); |
|
| 342 gtk_widget_show(vbox); |
|
| 343 |
|
| 344 /* add enabled / disabled */ |
|
| 345 button1 = gtk_radio_button_new_with_label(NULL, _("Enabled")); |
|
| 346 gtk_box_pack_start(GTK_BOX(vbox), button1, TRUE, TRUE, 0); |
|
| 347 gtk_widget_show(button1); |
|
| 348 |
|
| 349 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button1)); |
|
| 350 button2 = gtk_radio_button_new_with_label(group, _("Disabled")); |
|
| 351 gtk_box_pack_start(GTK_BOX(vbox), button2, TRUE, TRUE, 0); |
|
| 352 gtk_widget_show(button2); |
|
| 353 |
|
| 354 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button1), |
|
| 355 cc->features_state); |
|
| 356 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button2), |
|
| 357 !cc->features_state); |
|
| 358 g_signal_connect_swapped(G_OBJECT(button1), "toggled", |
|
| 359 G_CALLBACK(features_enable_cb), cc); |
|
| 360 |
|
| 361 /* add vbox for packing purposes */ |
|
| 362 vbox = gtk_vbox_new(TRUE, 0); |
|
| 363 gtk_box_pack_end(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); |
|
| 364 gtk_widget_show(vbox); |
|
| 365 |
|
| 366 /* add calibrate button */ |
|
| 367 button = gtk_button_new_with_label("Calibrate"); |
|
| 368 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, FALSE, 0); |
|
| 369 gtk_widget_show(button); |
|
| 370 |
|
| 371 gtk_widget_show(ret); |
|
| 372 |
|
| 373 return ret; |
|
| 374 } |
|
| 375 |
|
| 376 static void tcp_port_cb(GtkSpinButton *spin, struct crazychat *cc) |
|
| 377 { |
|
| 378 assert(spin); |
|
| 379 assert(cc); |
|
| 380 cc->tcp_port = gtk_spin_button_get_value_as_int(spin); |
|
| 381 Debug("New tcp port: %d\n", cc->tcp_port); |
|
| 382 } |
|
| 383 |
|
| 384 static void udp_port_cb(GtkSpinButton *spin, struct crazychat *cc) |
|
| 385 { |
|
| 386 assert(spin); |
|
| 387 assert(cc); |
|
| 388 cc->udp_port = gtk_spin_button_get_value_as_int(spin); |
|
| 389 Debug("New udp port: %d\n", cc->udp_port); |
|
| 390 } |
|
| 391 |
|
| 392 static void features_enable_cb(struct crazychat *cc) |
|
| 393 { |
|
| 394 Debug("Changing features state\n"); |
|
| 395 cc->features_state = !cc->features_state; |
|
| 396 if (cc->features_state) { |
|
| 397 cc->input_data = init_input(cc); |
|
| 398 } else { |
|
| 399 if (cc->input_data) { |
|
| 400 gtk_widget_destroy(cc->input_data->widget); |
|
| 401 } |
|
| 402 } |
|
| 403 } |
|
| 404 |
|
| 405 static gboolean cc_signed_on(GaimConnection *gc, void *plugin) |
|
| 406 { |
|
| 407 struct crazychat *extra; |
|
| 408 void *conv_handle; |
|
| 409 |
|
| 410 assert(plugin); |
|
| 411 extra = (struct crazychat*)((GaimPlugin*)plugin)->info->extra_info; |
|
| 412 gaim_signal_disconnect |
|
| 413 (gaim_connections_get_handle(), "signed-on", |
|
| 414 plugin, GAIM_CALLBACK(cc_signed_on)); |
|
| 415 gaim_signal_connect(GAIM_GTK_BLIST |
|
| 416 (gaim_get_blist()), |
|
| 417 "drawing-menu", plugin, |
|
| 418 GAIM_CALLBACK(cc_buddy_menu), NULL); |
|
| 419 conv_handle = gaim_conversations_get_handle(); |
|
| 420 gaim_signal_connect(conv_handle, "received-im-msg", plugin, |
|
| 421 GAIM_CALLBACK(receive_im_cb), extra); |
|
| 422 gaim_signal_connect(conv_handle, "displaying-im-msg", plugin, |
|
| 423 GAIM_CALLBACK(display_im_cb), extra); |
|
| 424 return FALSE; |
|
| 425 } |
|
| 426 |
|
| 427 static gboolean plugin_load(GaimPlugin *plugin) |
|
| 428 { |
|
| 429 GaimBuddyList *buddy_list; |
|
| 430 void *conv_handle; |
|
| 431 |
|
| 432 if (cc_init_gtk_gl()) |
|
| 433 return FALSE; |
|
| 434 |
|
| 435 cc_init(&cc_info); |
|
| 436 buddy_list = gaim_get_blist(); |
|
| 437 if (buddy_list) { |
|
| 438 gaim_signal_connect(GAIM_GTK_BLIST |
|
| 439 (buddy_list), |
|
| 440 "drawing-menu", plugin, |
|
| 441 GAIM_CALLBACK(cc_buddy_menu), NULL); |
|
| 442 conv_handle = gaim_conversations_get_handle(); |
|
| 443 gaim_signal_connect(conv_handle, "received-im-msg", plugin, |
|
| 444 GAIM_CALLBACK(receive_im_cb), &cc_info); |
|
| 445 gaim_signal_connect(conv_handle, "displaying-im-msg", plugin, |
|
| 446 GAIM_CALLBACK(display_im_cb), &cc_info); |
|
| 447 } else { |
|
| 448 gaim_signal_connect |
|
| 449 (gaim_connections_get_handle(), "signed-on", |
|
| 450 plugin, GAIM_CALLBACK(cc_signed_on), plugin); |
|
| 451 } |
|
| 452 |
|
| 453 Debug("CrazyChat plugin loaded.\n"); |
|
| 454 |
|
| 455 return TRUE; |
|
| 456 } |
|
| 457 |
|
| 458 static gboolean plugin_unload(GaimPlugin *plugin) |
|
| 459 { |
|
| 460 void *conv_handle; |
|
| 461 struct crazychat *extra; |
|
| 462 assert(plugin); |
|
| 463 extra = (struct crazychat*) plugin->info->extra_info; |
|
| 464 cc_destroy(extra); |
|
| 465 conv_handle = gaim_conversations_get_handle(); |
|
| 466 gaim_signal_disconnect(GAIM_GTK_BLIST |
|
| 467 (gaim_get_blist()), |
|
| 468 "drawing-menu", plugin, |
|
| 469 GAIM_CALLBACK(cc_buddy_menu)); |
|
| 470 gaim_signal_disconnect(conv_handle, "received-im", plugin, |
|
| 471 GAIM_CALLBACK(receive_im_cb)); |
|
| 472 gaim_signal_disconnect(conv_handle, "displaying-im-msg", plugin, |
|
| 473 GAIM_CALLBACK(display_im_cb)); |
|
| 474 Debug("CrazyChat plugin unloaded.\n"); |
|
| 475 return TRUE; |
|
| 476 } |
|
| 477 |
|
| 478 static void init_plugin(GaimPlugin *plugin) |
|
| 479 { |
|
| 480 gtk_gl_init(NULL, NULL); |
|
| 481 memset(&cc_info, 0, sizeof(cc_info)); |
|
| 482 Debug("CrazyChat plugin initialized\n"); |
|
| 483 } |
|
| 484 |
|
| 485 GAIM_INIT_PLUGIN(crazychat, init_plugin, info) |
|