1 /*
2 * Music messaging plugin for Purple
3 *
4 * Copyright (C) 2005 Christian Muise.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02111-1301, USA.
20 */
21
22 #include "internal.h"
23 #include "pidgin.h"
24
25 #include "conversation.h"
26
27 #include "gtkconv.h"
28 #include "gtkplugin.h"
29 #include "gtkutils.h"
30
31 #include "notify.h"
32 #include "version.h"
33 #include "debug.h"
34
35 #define DBUS_API_SUBJECT_TO_CHANGE
36 #include <dbus/dbus.h>
37 #include "dbus-maybe.h"
38 #include "dbus-bindings.h"
39 #include "dbus-server.h"
40 #include "dbus-purple.h"
41
42 #define MUSICMESSAGING_PLUGIN_ID "gtk-hazure-musicmessaging"
43 #define MUSICMESSAGING_PREFIX "##MM##"
44 #define MUSICMESSAGING_START_MSG _("A music messaging session has been requested. Please click the MM icon to accept.")
45 #define MUSICMESSAGING_CONFIRM_MSG _("Music messaging session confirmed.")
46
47 typedef struct {
48 PurpleConversation *conv; /* pointer to the conversation */
49 GtkWidget *seperator; /* seperator in the conversation */
50 GtkWidget *button; /* button in the conversation */
51 GPid pid; /* the pid of the score editor */
52
53 gboolean started; /* session has started and editor run */
54 gboolean originator; /* started the mm session */
55 gboolean requested; /* received a request to start a session */
56
57 } MMConversation;
58
59 static gboolean start_session(MMConversation *mmconv);
60 static void run_editor(MMConversation *mmconv);
61 static void kill_editor(MMConversation *mmconv);
62 static void add_button (MMConversation *mmconv);
63 static void remove_widget (GtkWidget *button);
64 static void init_conversation (PurpleConversation *conv);
65 static void conv_destroyed(PurpleConversation *conv);
66 static gboolean intercept_sent(PurpleAccount *account, const char *who, char **message, void* pData);
67 static gboolean intercept_received(PurpleAccount *account, char **sender, char **message, PurpleConversation *conv, int *flags);
68 static gboolean send_change_request (const int session, const char *id, const char *command, const char *parameters);
69 static gboolean send_change_confirmed (const int session, const char *command, const char *parameters);
70 static void session_end (MMConversation *mmconv);
71
72 /* Globals */
73 /* List of sessions */
74 static GList *conversations;
75
76 /* Pointer to this plugin */
77 static PurplePlugin *plugin_pointer;
78
79 /* Define types needed for DBus */
80 DBusGConnection *connection;
81 DBusGProxy *proxy;
82 #define DBUS_SERVICE_GSCORE "org.gscore.GScoreService"
83 #define DBUS_PATH_GSCORE "/org/gscore/GScoreObject"
84 #define DBUS_INTERFACE_GSCORE "org.gscore.GScoreInterface"
85
86 /* Define the functions to export for use with DBus */
87 DBUS_EXPORT void music_messaging_change_request (const int session, const char *command, const char *parameters);
88 DBUS_EXPORT void music_messaging_change_confirmed (const int session, const char *command, const char *parameters);
89 DBUS_EXPORT void music_messaging_change_failed (const int session, const char *id, const char *command, const char *parameters);
90 DBUS_EXPORT void music_messaging_done_session (const int session);
91
92 /* This file has been generated by the #dbus-analize-functions.py
93 script. It contains dbus wrappers for the four functions declared
94 above. */
95 #include "music-messaging-bindings.c"
96
97 /* Exported functions */
music_messaging_change_request(const int session,const char * command,const char * parameters)98 void music_messaging_change_request(const int session, const char *command, const char *parameters)
99 {
100
101 MMConversation *mmconv = (MMConversation *)g_list_nth_data(conversations, session);
102
103 if (mmconv->started)
104 {
105 if (mmconv->originator)
106 {
107 char *name = (mmconv->conv)->name;
108 send_change_request (session, name, command, parameters);
109 } else
110 {
111 GString *to_send = g_string_new("");
112 g_string_append_printf(to_send, "##MM## request %s %s##MM##", command, parameters);
113
114 purple_conv_im_send(PURPLE_CONV_IM(mmconv->conv), to_send->str);
115
116 purple_debug_misc("musicmessaging", "Sent request: %s\n", to_send->str);
117 }
118 }
119
120 }
121
music_messaging_change_confirmed(const int session,const char * command,const char * parameters)122 void music_messaging_change_confirmed(const int session, const char *command, const char *parameters)
123 {
124
125 MMConversation *mmconv = (MMConversation *)g_list_nth_data(conversations, session);
126
127 if (mmconv->started)
128 {
129 if (mmconv->originator)
130 {
131 GString *to_send = g_string_new("");
132 g_string_append_printf(to_send, "##MM## confirm %s %s##MM##", command, parameters);
133
134 purple_conv_im_send(PURPLE_CONV_IM(mmconv->conv), to_send->str);
135 } else
136 {
137 /* Do nothing. If they aren't the originator, then they can't confirm. */
138 }
139 }
140
141 }
142
music_messaging_change_failed(const int session,const char * id,const char * command,const char * parameters)143 void music_messaging_change_failed(const int session, const char *id, const char *command, const char *parameters)
144 {
145 MMConversation *mmconv = (MMConversation *)g_list_nth_data(conversations, session);
146
147 purple_notify_message(plugin_pointer, PURPLE_NOTIFY_MSG_INFO, command,
148 parameters, NULL, NULL, NULL);
149
150 if (mmconv->started)
151 {
152 if (mmconv->originator)
153 {
154 GString *to_send = g_string_new("");
155 g_string_append_printf(to_send, "##MM## failed %s %s %s##MM##", id, command, parameters);
156
157 purple_conv_im_send(PURPLE_CONV_IM(mmconv->conv), to_send->str);
158 } else
159 {
160 /* Do nothing. If they aren't the originator, then they can't confirm. */
161 }
162 }
163 }
164
music_messaging_done_session(const int session)165 void music_messaging_done_session(const int session)
166 {
167 MMConversation *mmconv = (MMConversation *)g_list_nth_data(conversations, session);
168
169 purple_notify_message(plugin_pointer, PURPLE_NOTIFY_MSG_INFO, "Session",
170 "Session Complete", NULL, NULL, NULL);
171
172 session_end(mmconv);
173 }
174
175
176 /* DBus commands that can be sent to the editor */
177 G_BEGIN_DECLS
178 DBusConnection *purple_dbus_get_connection(void);
179 G_END_DECLS
180
send_change_request(const int session,const char * id,const char * command,const char * parameters)181 static gboolean send_change_request (const int session, const char *id, const char *command, const char *parameters)
182 {
183 DBusMessage *message;
184
185 /* Create the signal we need */
186 message = dbus_message_new_signal (DBUS_PATH_PURPLE, DBUS_INTERFACE_PURPLE, "GscoreChangeRequest");
187
188 /* Append the string "Ping!" to the signal */
189 dbus_message_append_args (message,
190 DBUS_TYPE_INT32, &session,
191 DBUS_TYPE_STRING, &id,
192 DBUS_TYPE_STRING, &command,
193 DBUS_TYPE_STRING, ¶meters,
194 DBUS_TYPE_INVALID);
195
196 /* Send the signal */
197 dbus_connection_send (purple_dbus_get_connection(), message, NULL);
198
199 /* Free the signal now we have finished with it */
200 dbus_message_unref (message);
201
202 /* Tell the user we sent a signal */
203 g_printerr("Sent change request signal: %d %s %s %s\n", session, id, command, parameters);
204
205 return TRUE;
206 }
207
send_change_confirmed(const int session,const char * command,const char * parameters)208 static gboolean send_change_confirmed (const int session, const char *command, const char *parameters)
209 {
210 DBusMessage *message;
211
212 /* Create the signal we need */
213 message = dbus_message_new_signal (DBUS_PATH_PURPLE, DBUS_INTERFACE_PURPLE, "GscoreChangeConfirmed");
214
215 /* Append the string "Ping!" to the signal */
216 dbus_message_append_args (message,
217 DBUS_TYPE_INT32, &session,
218 DBUS_TYPE_STRING, &command,
219 DBUS_TYPE_STRING, ¶meters,
220 DBUS_TYPE_INVALID);
221
222 /* Send the signal */
223 dbus_connection_send (purple_dbus_get_connection(), message, NULL);
224
225 /* Free the signal now we have finished with it */
226 dbus_message_unref (message);
227
228 /* Tell the user we sent a signal */
229 g_printerr("Sent change confirmed signal.\n");
230
231 return TRUE;
232 }
233
234
235 static int
mmconv_from_conv_loc(PurpleConversation * conv)236 mmconv_from_conv_loc(PurpleConversation *conv)
237 {
238 GList *l;
239 MMConversation *mmconv_current = NULL;
240 guint i;
241
242 i = 0;
243 for (l = conversations; l != NULL; l = l->next)
244 {
245 mmconv_current = l->data;
246 if (conv == mmconv_current->conv)
247 {
248 return i;
249 }
250 i++;
251 }
252 return -1;
253 }
254
255 static MMConversation*
mmconv_from_conv(PurpleConversation * conv)256 mmconv_from_conv(PurpleConversation *conv)
257 {
258 return (MMConversation *)g_list_nth_data(conversations, mmconv_from_conv_loc(conv));
259 }
260
261 static gboolean
plugin_load(PurplePlugin * plugin)262 plugin_load(PurplePlugin *plugin) {
263 void *conv_list_handle;
264
265 PURPLE_DBUS_RETURN_FALSE_IF_DISABLED(plugin);
266
267 /* First, we have to register our four exported functions with the
268 main purple dbus loop. Without this statement, the purple dbus
269 code wouldn't know about our functions. */
270 PURPLE_DBUS_REGISTER_BINDINGS(plugin);
271
272 /* Keep the plugin for reference (needed for notify's) */
273 plugin_pointer = plugin;
274
275 /* Add the button to all the current conversations */
276 purple_conversation_foreach (init_conversation);
277
278 /* Listen for any new conversations */
279 conv_list_handle = purple_conversations_get_handle();
280
281 purple_signal_connect(conv_list_handle, "conversation-created",
282 plugin, PURPLE_CALLBACK(init_conversation), NULL);
283
284 /* Listen for conversations that are ending */
285 purple_signal_connect(conv_list_handle, "deleting-conversation",
286 plugin, PURPLE_CALLBACK(conv_destroyed), NULL);
287
288 /* Listen for sending/receiving messages to replace tags */
289 purple_signal_connect(conv_list_handle, "sending-im-msg",
290 plugin, PURPLE_CALLBACK(intercept_sent), NULL);
291 purple_signal_connect(conv_list_handle, "receiving-im-msg",
292 plugin, PURPLE_CALLBACK(intercept_received), NULL);
293
294 return TRUE;
295 }
296
297 static gboolean
plugin_unload(PurplePlugin * plugin)298 plugin_unload(PurplePlugin *plugin) {
299 MMConversation *mmconv = NULL;
300
301 while (conversations != NULL)
302 {
303 mmconv = conversations->data;
304 conv_destroyed(mmconv->conv);
305 }
306 return TRUE;
307 }
308
309
310
311 static gboolean
intercept_sent(PurpleAccount * account,const char * who,char ** message,void * pData)312 intercept_sent(PurpleAccount *account, const char *who, char **message, void* pData)
313 {
314 if (message == NULL || *message == NULL || **message == '\0')
315 return FALSE;
316
317 if (0 == strncmp(*message, MUSICMESSAGING_PREFIX, strlen(MUSICMESSAGING_PREFIX)))
318 {
319 purple_debug_misc("purple-musicmessaging", "Sent MM Message: %s\n", *message);
320 message = 0;
321 }
322 else if (0 == strncmp(*message, MUSICMESSAGING_START_MSG, strlen(MUSICMESSAGING_START_MSG)))
323 {
324 purple_debug_misc("purple-musicmessaging", "Sent MM request.\n");
325 return FALSE;
326 }
327 else if (0 == strncmp(*message, MUSICMESSAGING_CONFIRM_MSG, strlen(MUSICMESSAGING_CONFIRM_MSG)))
328 {
329 purple_debug_misc("purple-musicmessaging", "Sent MM confirm.\n");
330 return FALSE;
331 }
332 else if (0 == strncmp(*message, "test1", strlen("test1")))
333 {
334 purple_debug_misc("purple-musicmessaging", "\n\nTEST 1\n\n");
335 send_change_request(0, "test-id", "test-command", "test-parameters");
336 return FALSE;
337 }
338 else if (0 == strncmp(*message, "test2", strlen("test2")))
339 {
340 purple_debug_misc("purple-musicmessaging", "\n\nTEST 2\n\n");
341 send_change_confirmed(1, "test-command", "test-parameters");
342 return FALSE;
343 }
344 else
345 {
346 return FALSE;
347 /* Do nothing...procceed as normal */
348 }
349 return TRUE;
350 }
351
352 static gboolean
intercept_received(PurpleAccount * account,char ** sender,char ** message,PurpleConversation * conv,int * flags)353 intercept_received(PurpleAccount *account, char **sender, char **message, PurpleConversation *conv, int *flags)
354 {
355 MMConversation *mmconv;
356
357 if (conv == NULL) {
358 /* XXX: This is just to avoid a crash (#2726).
359 * We may want to create the conversation instead of returning from here
360 */
361 return FALSE;
362 }
363
364 mmconv = mmconv_from_conv(conv);
365
366 purple_debug_misc("purple-musicmessaging", "Intercepted: %s\n", *message);
367 if (strstr(*message, MUSICMESSAGING_PREFIX))
368 {
369 char *parsed_message = strtok(strstr(*message, MUSICMESSAGING_PREFIX), "<");
370 purple_debug_misc("purple-musicmessaging", "Received an MM Message: %s\n", parsed_message);
371
372 if (mmconv->started)
373 {
374 if (strstr(parsed_message, "request"))
375 {
376 if (mmconv->originator)
377 {
378 int session = mmconv_from_conv_loc(conv);
379 char *id = (mmconv->conv)->name;
380 char *command;
381 char *parameters;
382
383 purple_debug_misc("purple-musicmessaging", "Sending request to gscore.\n");
384
385 /* Get past the first two terms - '##MM##' and 'request' */
386 strtok(parsed_message, " "); /* '##MM##' */
387 strtok(NULL, " "); /* 'request' */
388
389 command = strtok(NULL, " ");
390 parameters = strtok(NULL, "#");
391
392 send_change_request (session, id, command, parameters);
393
394 }
395 } else if (strstr(parsed_message, "confirm"))
396 {
397 if (!mmconv->originator)
398 {
399 int session = mmconv_from_conv_loc(conv);
400 char *command;
401 char *parameters;
402
403 purple_debug_misc("purple-musicmessaging", "Sending confirmation to gscore.\n");
404
405 /* Get past the first two terms - '##MM##' and 'confirm' */
406 strtok(parsed_message, " "); /* '##MM##' */
407 strtok(NULL, " "); /* 'confirm' */
408
409 command = strtok(NULL, " ");
410 parameters = strtok(NULL, "#");
411
412 send_change_confirmed (session, command, parameters);
413 }
414 } else if (strstr(parsed_message, "failed"))
415 {
416 char *id;
417 char *command;
418
419 /* Get past the first two terms - '##MM##' and 'confirm' */
420 strtok(parsed_message, " "); /* '##MM##' */
421 strtok(NULL, " "); /* 'failed' */
422
423 id = strtok(NULL, " ");
424 command = strtok(NULL, " ");
425 /* char *parameters = strtok(NULL, "#"); DONT NEED PARAMETERS */
426
427 if ((mmconv->conv)->name == id)
428 {
429 purple_notify_message(plugin_pointer, PURPLE_NOTIFY_MSG_ERROR,
430 _("Music Messaging"),
431 _("There was a conflict in running the command:"), command, NULL, NULL);
432 }
433 }
434 }
435
436 message = 0;
437 }
438 else if (strstr(*message, MUSICMESSAGING_START_MSG))
439 {
440 purple_debug_misc("purple-musicmessaging", "Received MM request.\n");
441 if (!(mmconv->originator))
442 {
443 mmconv->requested = TRUE;
444 return FALSE;
445 }
446
447 }
448 else if (strstr(*message, MUSICMESSAGING_CONFIRM_MSG))
449 {
450 purple_debug_misc("purple-musicmessagin", "Received MM confirm.\n");
451
452 if (mmconv->originator)
453 {
454 start_session(mmconv);
455 return FALSE;
456 }
457 }
458 else
459 {
460 return FALSE;
461 /* Do nothing. */
462 }
463 return TRUE;
464 }
465
send_request(MMConversation * mmconv)466 static void send_request(MMConversation *mmconv)
467 {
468 PurpleConnection *connection = purple_conversation_get_gc(mmconv->conv);
469 const char *convName = purple_conversation_get_name(mmconv->conv);
470 serv_send_im(connection, convName, MUSICMESSAGING_START_MSG, PURPLE_MESSAGE_SEND);
471 }
472
send_request_confirmed(MMConversation * mmconv)473 static void send_request_confirmed(MMConversation *mmconv)
474 {
475 PurpleConnection *connection = purple_conversation_get_gc(mmconv->conv);
476 const char *convName = purple_conversation_get_name(mmconv->conv);
477 serv_send_im(connection, convName, MUSICMESSAGING_CONFIRM_MSG, PURPLE_MESSAGE_SEND);
478 }
479
480
481 static gboolean
start_session(MMConversation * mmconv)482 start_session(MMConversation *mmconv)
483 {
484 run_editor(mmconv);
485 return TRUE;
486 }
487
session_end(MMConversation * mmconv)488 static void session_end (MMConversation *mmconv)
489 {
490 mmconv->started = FALSE;
491 mmconv->originator = FALSE;
492 mmconv->requested = FALSE;
493 kill_editor(mmconv);
494 }
495
music_button_toggled(GtkWidget * widget,gpointer data)496 static void music_button_toggled (GtkWidget *widget, gpointer data)
497 {
498 MMConversation *mmconv = mmconv_from_conv(((MMConversation *) data)->conv);
499 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
500 {
501 if (((MMConversation *) data)->requested)
502 {
503 start_session(mmconv);
504 send_request_confirmed(mmconv);
505 }
506 else
507 {
508 ((MMConversation *) data)->originator = TRUE;
509 send_request((MMConversation *) data);
510 }
511 } else {
512 session_end((MMConversation *)data);
513 }
514 }
515
set_editor_path(GtkWidget * button,GtkWidget * text_field)516 static void set_editor_path (GtkWidget *button, GtkWidget *text_field)
517 {
518 const char * path = gtk_entry_get_text((GtkEntry*)text_field);
519 purple_prefs_set_string("/plugins/gtk/musicmessaging/editor_path", path);
520
521 }
522
run_editor(MMConversation * mmconv)523 static void run_editor (MMConversation *mmconv)
524 {
525 GError *spawn_error = NULL;
526 GString *session_id;
527 gchar * args[4];
528 args[0] = (gchar *)purple_prefs_get_string("/plugins/gtk/musicmessaging/editor_path");
529
530 args[1] = "-session_id";
531 session_id = g_string_new("");
532 g_string_append_printf(session_id, "%d", mmconv_from_conv_loc(mmconv->conv));
533 args[2] = session_id->str;
534
535 args[3] = NULL;
536
537 if (!(g_spawn_async (".", args, NULL, 4, NULL, NULL, &(mmconv->pid), &spawn_error)))
538 {
539 purple_notify_error(plugin_pointer, _("Error Running Editor"),
540 _("The following error has occurred:"), spawn_error->message);
541 mmconv->started = FALSE;
542 }
543 else
544 {
545 mmconv->started = TRUE;
546 }
547 }
548
kill_editor(MMConversation * mmconv)549 static void kill_editor (MMConversation *mmconv)
550 {
551 if (mmconv->pid)
552 {
553 kill(mmconv->pid, SIGINT);
554 mmconv->pid = 0;
555 }
556 }
557
init_conversation(PurpleConversation * conv)558 static void init_conversation (PurpleConversation *conv)
559 {
560 MMConversation *mmconv;
561 mmconv = g_malloc(sizeof(MMConversation));
562
563 mmconv->conv = conv;
564 mmconv->started = FALSE;
565 mmconv->originator = FALSE;
566 mmconv->requested = FALSE;
567
568 add_button(mmconv);
569
570 conversations = g_list_append(conversations, mmconv);
571 }
572
conv_destroyed(PurpleConversation * conv)573 static void conv_destroyed (PurpleConversation *conv)
574 {
575 MMConversation *mmconv = mmconv_from_conv(conv);
576
577 remove_widget(mmconv->button);
578 remove_widget(mmconv->seperator);
579 if (mmconv->started)
580 {
581 kill_editor(mmconv);
582 }
583 conversations = g_list_remove(conversations, mmconv);
584 }
585
add_button(MMConversation * mmconv)586 static void add_button (MMConversation *mmconv)
587 {
588 PurpleConversation *conv = mmconv->conv;
589
590 GtkWidget *button, *image, *sep;
591 gchar *file_path;
592
593 button = gtk_toggle_button_new();
594 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
595
596 g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(music_button_toggled), mmconv);
597
598 file_path = g_build_filename(DATADIR, "pixmaps", "purple", "buttons",
599 "music.png", NULL);
600 image = gtk_image_new_from_file(file_path);
601 g_free(file_path);
602
603 gtk_container_add((GtkContainer *)button, image);
604
605 sep = gtk_vseparator_new();
606
607 mmconv->seperator = sep;
608 mmconv->button = button;
609
610 gtk_widget_show(sep);
611 gtk_widget_show(image);
612 gtk_widget_show(button);
613
614 gtk_box_pack_start(GTK_BOX(PIDGIN_CONVERSATION(conv)->toolbar), sep, FALSE, FALSE, 0);
615 gtk_box_pack_start(GTK_BOX(PIDGIN_CONVERSATION(conv)->toolbar), button, FALSE, FALSE, 0);
616 }
617
remove_widget(GtkWidget * button)618 static void remove_widget (GtkWidget *button)
619 {
620 gtk_widget_hide(button);
621 gtk_widget_destroy(button);
622 }
623
624 static GtkWidget *
get_config_frame(PurplePlugin * plugin)625 get_config_frame(PurplePlugin *plugin)
626 {
627 GtkWidget *ret;
628 GtkWidget *vbox;
629
630 GtkWidget *editor_path;
631 GtkWidget *editor_path_label;
632 GtkWidget *editor_path_button;
633
634 /* Outside container */
635 ret = gtk_vbox_new(FALSE, 18);
636 gtk_container_set_border_width(GTK_CONTAINER(ret), 10);
637
638 /* Configuration frame */
639 vbox = pidgin_make_frame(ret, _("Music Messaging Configuration"));
640
641 /* Path to the score editor */
642 editor_path = gtk_entry_new();
643 editor_path_label = gtk_label_new(_("Score Editor Path"));
644 editor_path_button = gtk_button_new_with_mnemonic(_("_Apply"));
645
646 gtk_entry_set_text((GtkEntry*)editor_path, "/usr/local/bin/gscore");
647
648 g_signal_connect(G_OBJECT(editor_path_button), "clicked",
649 G_CALLBACK(set_editor_path), editor_path);
650
651 gtk_box_pack_start(GTK_BOX(vbox), editor_path_label, FALSE, FALSE, 0);
652 gtk_box_pack_start(GTK_BOX(vbox), editor_path, FALSE, FALSE, 0);
653 gtk_box_pack_start(GTK_BOX(vbox), editor_path_button, FALSE, FALSE, 0);
654
655 gtk_widget_show_all(ret);
656
657 return ret;
658 }
659
660 static PidginPluginUiInfo ui_info =
661 {
662 get_config_frame,
663 0, /* page_num (reserved) */
664
665 /* padding */
666 NULL,
667 NULL,
668 NULL,
669 NULL
670 };
671
672 static PurplePluginInfo info = {
673 PURPLE_PLUGIN_MAGIC,
674 PURPLE_MAJOR_VERSION,
675 PURPLE_MINOR_VERSION,
676 PURPLE_PLUGIN_STANDARD, /**< type */
677 PIDGIN_PLUGIN_TYPE, /**< ui_requirement */
678 0, /**< flags */
679 NULL, /**< dependencies */
680 PURPLE_PRIORITY_DEFAULT, /**< priority */
681
682 MUSICMESSAGING_PLUGIN_ID, /**< id */
683 "Music Messaging", /**< name */
684 DISPLAY_VERSION, /**< version */
685 N_("Music Messaging Plugin for collaborative composition."),
686 /** summary */
687 N_("The Music Messaging Plugin allows a number of users to simultaneously "
688 "work on a piece of music by editing a common score in real-time."),
689 /** description */
690 "Christian Muise <christian.muise@gmail.com>", /**< author */
691 PURPLE_WEBSITE, /**< homepage */
692 plugin_load, /**< load */
693 plugin_unload, /**< unload */
694 NULL, /**< destroy */
695 &ui_info, /**< ui_info */
696 NULL, /**< extra_info */
697 NULL,
698 NULL,
699
700 /* padding */
701 NULL,
702 NULL,
703 NULL,
704 NULL
705 };
706
707 static void
init_plugin(PurplePlugin * plugin)708 init_plugin(PurplePlugin *plugin) {
709 purple_prefs_add_none("/plugins/gtk/musicmessaging");
710 purple_prefs_add_string("/plugins/gtk/musicmessaging/editor_path", "/usr/bin/gscore");
711 }
712
713 PURPLE_INIT_PLUGIN(musicmessaging, init_plugin, info);
714