@p maximum_input_line_length = 132 @p maximum_output_line_length = 132 @O@==@{@- #define PURPLE_PLUGINS #include "conversation.h" #include "internal.h" #include "plugin.h" #include "signals.h" #include "sound.h" #include "util.h" #include "version.h" #define DIM(_vec_) (sizeof(_vec_) / sizeof((_vec_)[0])) //------------------------------------------------------------------------------ typedef struct _Call Call; struct _Call { Call *next; Call *prev; PurpleConversation *caller; gboolean answered; }; //------------------------------------------------------------------------------ static Call *g_calls_head = 0; static Call *g_calls_tail = 0; //------------------------------------------------------------------------------ static gboolean g_ringer_on = FALSE; //------------------------------------------------------------------------------ static gboolean ring_if_unanswered() { gboolean found_unanswered = FALSE; for (Call *curr = g_calls_head->next; curr != g_calls_tail; curr = curr->next) { if (FALSE == curr->answered && FALSE == found_unanswered) { purple_sound_play_event( PURPLE_SOUND_FIRST_RECEIVE, purple_conversation_get_account(curr->caller)); found_unanswered = TRUE; } } g_ringer_on = found_unanswered; return g_ringer_on; } //------------------------------------------------------------------------------ static void start_ringing(PurpleAccount *acct) { if (FALSE == g_ringer_on) { purple_timeout_add(30 * 1000, ring_if_unanswered, 0); g_ringer_on = TRUE; } } //------------------------------------------------------------------------------ static void init_calls() { g_calls_head = g_new0(Call, 1); g_calls_tail = g_new0(Call, 1); g_calls_head->next = g_calls_tail; g_calls_head->prev = 0; g_calls_tail->next = g_calls_tail; g_calls_tail->prev = g_calls_head; } //------------------------------------------------------------------------------ static void delete_call(Call *call) { call->next->prev = call->prev; call->prev->next = call->next; g_free(call); } //------------------------------------------------------------------------------ static void deleting_conversation_cb(PurpleConversation *conv) { Call *curr = g_calls_head->next; while (g_calls_tail != curr) { Call *next = curr->next; if (curr->caller == conv) { delete_call(curr); } curr = next; } } //------------------------------------------------------------------------------ static Call *place_call(PurpleConversation *caller) { Call *call = g_new0(Call, 1); call->caller = caller; call->answered = FALSE; call->next = g_calls_tail; call->prev = g_calls_tail->prev; call->prev->next = call; g_calls_tail->prev = call; start_ringing(purple_conversation_get_account(caller)); return call; } //------------------------------------------------------------------------------ static gboolean is_routed(PurpleConversation *conv) { for (Call *curr = g_calls_head->next; curr != g_calls_tail; curr = curr->next) { if (curr->caller == conv) { return TRUE; } } return FALSE; } //------------------------------------------------------------------------------ static void ring_operators(PurpleConversation *conv) { place_call(conv); } //------------------------------------------------------------------------------ static void hangup_related_calls(Call *call) { call->answered = TRUE; } //------------------------------------------------------------------------------ static GSList *get_forwarding_conversations(PurpleConversation *conv) { if (! is_routed(conv)) { ring_operators(conv); } GSList *forwards = 0; for (Call *curr = g_calls_head->next; curr != g_calls_tail; curr = curr->next) { if (curr->caller == conv) { forwards = g_slist_prepend(forwards, 0); } } return forwards; } //------------------------------------------------------------------------------ static void sending_im_msg_cb(PurpleAccount *account, char *recipient, char **buffer) { PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, recipient, account); Call *local = 0; for (Call *curr = g_calls_head->next; curr != g_calls_tail; curr = curr->next) { if (curr->caller == conv) { local = curr; break; } } if (0 != local) { hangup_related_calls(local); } } //------------------------------------------------------------------------------ static gboolean receiving_im_msg_cb(PurpleAccount *account , char **sender , char **message , PurpleConversation *conv , PurpleMessageFlags *flags) { if (0 == conv) { conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, *sender); } GSList *forwards = get_forwarding_conversations(conv); g_slist_free(forwards); return FALSE; } //------------------------------------------------------------------------------ static void connect_conv_callbacks(PurplePlugin *plugin) { static struct { char *name; PurpleCallback func; } callbacks[] = { { "deleting-conversation" , PURPLE_CALLBACK(deleting_conversation_cb) } , { "receiving-im-msg" , PURPLE_CALLBACK(receiving_im_msg_cb) } , { "sending-im-msg" , PURPLE_CALLBACK(sending_im_msg_cb) } }; void *conv_handle = purple_conversations_get_handle(); for (int i = 0; i < DIM(callbacks); ++i) { purple_signal_connect(conv_handle, callbacks[i].name, plugin, callbacks[i].func, NULL); } } //------------------------------------------------------------------------------ static void connect_callbacks(PurplePlugin *plugin) { connect_conv_callbacks(plugin); } //------------------------------------------------------------------------------ // Always allow users to contact us. static void always_authorize(PurpleAccount *account , const char *remote_user , const char *id , const char *alias , const char *message , gboolean on_list , GCallback authorize_cb , GCallback deny_cb , void *user_data) { ((void (*)(void *)) authorize_cb)(user_data); } //------------------------------------------------------------------------------ static gboolean plugin_load(PurplePlugin *plugin) { init_calls(); connect_callbacks(plugin); PurpleAccountUiOps *acctOps = purple_accounts_get_ui_ops(); acctOps->request_authorize = always_authorize; purple_accounts_set_ui_ops(acctOps); return TRUE; } //------------------------------------------------------------------------------ static gboolean plugin_unload(PurplePlugin *plugin) { return TRUE; } //------------------------------------------------------------------------------ static PurplePluginInfo info = { PURPLE_PLUGIN_MAGIC , PURPLE_MAJOR_VERSION , PURPLE_MINOR_VERSION , PURPLE_PLUGIN_STANDARD // type , NULL // ui_requirement , 0 // flags , NULL // dependencies , PURPLE_PRIORITY_DEFAULT // priority , N_("core-nubgames-pidgin4lib") // id , N_("pidgin4lib") // name , N_("0.4") // version // summary , N_("Additional IM features targeted toward libraries.") // description , N_("Automatically authorizes Jabber and MSN buddy requests. Repeats" " new message sound alert every 30 seconds until one response is sent.") , "Pam Sessoms " // author , "http://www.lib.unc.edu/reference/eref/pidgin/" // homepage , plugin_load // load , plugin_unload // unload , NULL // destroy , NULL // ui_info , NULL // extra_info , NULL , NULL }; //------------------------------------------------------------------------------ static void init_plugin(PurplePlugin *plugin) { } //------------------------------------------------------------------------------ PURPLE_INIT_PLUGIN(pidgin4lib, init_plugin, info); @}