diff options
author | bill auger <mr.j.spam.me@gmail.com> | 2013-09-10 19:52:23 -0400 |
---|---|---|
committer | bill auger <mr.j.spam.me@gmail.com> | 2013-09-10 19:52:23 -0400 |
commit | b70b43e1fe21766ed37c743b27c765ac9e216948 (patch) | |
tree | 044d168b6bf66395903402f7095c434049288ec9 | |
parent | 2babc935b0c1f911689112e838dfd3a036c01142 (diff) |
reimplement add command and status reporting
-rw-r--r-- | README.md | 57 | ||||
-rw-r--r-- | bridgin.c | 375 | ||||
-rw-r--r-- | bridgin.dbg.h | 35 | ||||
-rw-r--r-- | bridgin.h | 167 | ||||
-rwxr-xr-x | install | 28 |
5 files changed, 568 insertions, 94 deletions
@@ -14,5 +14,60 @@ some new functionalities this will allow: * better handling of special forms such as '/me' , smileys , etc ... * issuing admin commands in the standard form ('/add' instead of '?/add') * painfree installation and automatic loading with pidgin -* running on a headless box +* running on a nox box * running on a windows box + + +##build instructions for debian (ymmv) + +cd into your build dir and load sources and deps + + apt-get source pidgin + sudo apt-get build-dep pidgin + +cd into ./pidgin-x.x.x/ and build pidgin and finch +if you already have pidgin or finch installed +you can delete this build afterward +it is needed only to simplify building the bridgin plugin + + ./configure + make all + +now go make some C(__) and when the build has completed +copy the contents of this repo into ./libpurple/plugins +cd into ./libpurple/plugins and run the install script + + chmod a+x ./install && ./install + +if your $HOME environment variable is properly set +the install script should reply with the following message +and pidgin will launch automatically + + "compilation success - installing to YOUR_HOME_DIR/.purple/plugins/" + +check that the install location mentioned points to inside you home dir +and that the plugin was installed properly + + ls $HOME/.purple/plugins/bridgin.so + +if there is no output then you will need to manually copy the file 'bridgin.so' +into YOUR_HOME_DIR/.purple/plugins/ or /usr/lib/purple-2/ + +if you are running without X or you do not want pidgin to launch automatically +use this comand to compile and install only + + ./install nolaunch + +if you do not want the plugin to be automatically installed into your home dir +use this comand to compile only + + make bridgin.so + + +## window build instructions +follow [these instructions](https://test.developer.pidgin.im/wiki/BuildingWinPidgin) to build pidgin for windows +then copy the contents of this repo into PIDGIN_SRC_DIR\libpurple\plugins +cd into PIDGIN_SRC_DIR\libpurple\plugins then make and install with: + + make -f Makefile.mingw bridgin.dll + copy bridgin.dll %APPDATA%\.purple\plugins @@ -2,69 +2,202 @@ #include "bridgin.h" #include "bridgin.dbg.h" + /* helpers */ -PurpleCmdId RegisterCmd(const char* command , const char* format , +PurpleCmdId registerCmd(const char* command , const char* format , PurpleCmdRet (* callback)() , const char* help) { return purple_cmd_register(command , format , PURPLE_CMD_P_DEFAULT , PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT , PLUGIN_ID , callback , help , NULL) ; } -void SystemChat(PurpleConversation* conv , const char* msg) +void alert(char* msg) +{ + purple_notify_message(ThisPlugin , PURPLE_NOTIFY_MSG_INFO , msg , + PLUGIN_VERSION , NULL , NULL , NULL) ; +} + +gboolean isBlank(const char* aCstring) { return (!aCstring || !*aCstring) ; } + + +/* model helpers */ + +Bridge* newBridge(char* bridgeName) +{ + Bridge* bridge ; Channel* channel ; + + bridge = (Bridge*) malloc(sizeof(Bridge)) ; if (!bridge) return NULL ; + channel = (Channel*)malloc(sizeof(Channel)) ; if (!channel) return NULL ; + + bridge->name = bridgeName ; + bridge->isEnabled = TRUE ; + bridge->next = NULL ; + bridge->sentinelChannel = channel ; + + channel->name = "sentinel" ; + channel->protocol[0] = '\0' ; + channel->account = NULL ; + channel->username = "" ; + channel->conv = NULL ; + channel->isActive = FALSE ; + channel->next = NULL ; + + return bridge ; +} + +Channel* newChannel(PurpleConversation* conv) { - purple_conversation_write(conv , BRIDGIN_NICK , msg , PURPLE_MESSAGE_SYSTEM , time(0)) ; + Channel* channel ; PurpleAccount* account ; + const char* protocol ; char* network ; + + channel = (Channel*)malloc(sizeof(Channel)) ; if (!channel) return NULL ; + + // append network url to protocol + account = getAccount(conv) ; protocol = getProtocol(account) ; + if (!strcmp(protocol , IRC_PROTOCOL) && (network = strstr(getUsername(account) , "@"))) + snprintf(channel->protocol , PROTOCOL_BUFFER_SIZE , "%s%s" , protocol , network) ; + else strncpy(channel->protocol , protocol , PROTOCOL_BUFFER_SIZE) ; + + channel->name = getChannelName(conv) ; + channel->account = account ; + channel->username = getNick(account) ; + channel->conv = conv ; + channel->isActive = TRUE ; + channel->next = NULL ; + + return channel ; +} + +Bridge* getBridgeByChannel(PurpleConversation* conv) +{ + Bridge* bridge ; Channel* channel ; + + bridge = SentinelBridge ; + while (bridge->next) + { + channel = (bridge = bridge->next)->sentinelChannel ; + while (channel->next) + if ((channel = channel->next)->conv == conv) +{ +DBGss("getBridgeByChannel() '" , getChannelName(conv) , "' found" , "") ; + + return bridge ; +} + } +DBGss("getBridgeByChannel() '" , getChannelName(conv) , "' not found" , "") ; + + return SentinelBridge ; +} + +Bridge* getBridgeByName(char* bridgeName) +{ + Bridge* bridge ; + + bridge = SentinelBridge ; + while (bridge->next) + if (!strcmp((bridge = bridge->next)->name , bridgeName)) +{ +DBGss("getBridgeByName() '" , bridgeName , "' found" , "") ; + + return bridge ; +} +DBGss("getBridgeByName() '" , bridgeName , "' not found" , "") ; + + return SentinelBridge ; +} + +const char* getChannelName(PurpleConversation* conv) { return purple_conversation_get_name(conv) ; } + +const char* getProtocol(PurpleAccount *account) { return purple_account_get_protocol_name(account) ; } + +PurpleAccount* getAccount(PurpleConversation* conv) { return purple_conversation_get_account(conv) ; } + +const char* getUsername(PurpleAccount *account) { return purple_account_get_username(account) ; } + +const char* getNick(PurpleAccount *account) { return purple_account_get_name_for_display(account) ; } + +void setChannel(char* bridgeName , PurpleConversation* conv) +{ + Bridge* bridge ; Channel* channel ; + + if ((bridge = getBridgeByName(bridgeName)) == SentinelBridge) + { + while (bridge->next) bridge = bridge->next ; + bridge->next = newBridge(bridgeName) ; if (!bridge->next) { alert(OOM_MSG) ; return ; } + + bridge = bridge->next ; + } + channel = bridge->sentinelChannel ; + while (channel->next) channel = channel->next ; + channel->next = newChannel(conv) ; if (!channel->next) alert(OOM_MSG) ; +} + +void storeSession() {} // TODO: + +unsigned int getNBridges() +{ + Bridge* bridge ; unsigned int n ; bridge = SentinelBridge ; n = 0 ; + while ((bridge = bridge->next)) ++n ; + return n ; +} + +unsigned int getNChannels(Bridge* bridge) +{ + Channel* channel ; unsigned int n ; channel = bridge->sentinelChannel ; n = 0 ; + while ((channel = channel->next)) ++n ; + return n ; } /* event handlers */ -void HandlePluginInit(PurplePlugin *plugin) {} +void handlePluginInit(PurplePlugin* plugin) { SentinelBridge = newBridge("sentinel") ; } -gboolean HandlePluginLoaded(PurplePlugin *aPlugin) +gboolean handlePluginLoaded(PurplePlugin* aPlugin) { -// purple_notify_message(aPlugin , PURPLE_NOTIFY_MSG_INFO , "Hello Pidgin!" , PLUGIN_VERSION , NULL , NULL , NULL) ; + ThisPlugin = aPlugin ; purple_signal_connect(purple_conversations_get_handle() , "received-im-msg" , - aPlugin , PURPLE_CALLBACK(HandleIm) , NULL) ; + aPlugin , PURPLE_CALLBACK(handleIm) , NULL) ; purple_signal_connect(purple_conversations_get_handle() , "received-chat-msg" , - aPlugin , PURPLE_CALLBACK(HandleChat) , NULL) ; + aPlugin , PURPLE_CALLBACK(handleChat) , NULL) ; purple_signal_connect(purple_conversations_get_handle() , "deleting-conversation" , - aPlugin , PURPLE_CALLBACK(HandleChannelClosed) , NULL) ; - - CommandIds[0] = RegisterCmd(ADD_CMD , UNARY_FMT , ADD_CB , ADDu_HELP) ; - CommandIds[1] = RegisterCmd(ADD_CMD , BINARY_FMT , ADD_CB , ADDb_HELP) ; - CommandIds[2] = RegisterCmd(REMOVE_CMD , UNARY_FMT , REMOVE_CB , REMOVE_HELP) ; - CommandIds[3] = RegisterCmd(DISABLE_CMD , UNARY_FMT , ENABLE_CB , DISABLEu_HELP) ; - CommandIds[4] = RegisterCmd(DISABLE_CMD , BINARY_FMT , ENABLE_CB , DISABLEb_HELP) ; - CommandIds[5] = RegisterCmd(ENABLE_CMD , UNARY_FMT , ENABLE_CB , ENABLEu_HELP) ; - CommandIds[6] = RegisterCmd(ENABLE_CMD , BINARY_FMT , ENABLE_CB , ENABLEb_HELP) ; - CommandIds[7] = RegisterCmd(ECHO_CMD , BINARY_FMT , ECHO_CB , ECHO_HELP) ; - CommandIds[8] = RegisterCmd(CHAT_CMD , BINARY_FMT , CHAT_CB , CHAT_HELP) ; - CommandIds[9] = RegisterCmd(BCAST_CMD , BINARY_FMT , BCAST_CB , BCAST_HELP) ; - CommandIds[10] = RegisterCmd(STATUS_CMD , UNARY_FMT , STATUS_CB , STATUSu_HELP) ; - CommandIds[11] = RegisterCmd(STATUS_CMD , BINARY_FMT , STATUS_CB , STATUSb_HELP) ; - CommandIds[12] = RegisterCmd(HELP_CMD , UNARY_FMT , HELP_CB , HELP_HELP) ; - - return TRUE ; + aPlugin , PURPLE_CALLBACK(handleChannelClosed) , NULL) ; + + CommandIds[0] = registerCmd(ADD_CMD , UNARY_FMT , ADD_CB , ADDu_HELP) ; + CommandIds[1] = registerCmd(ADD_CMD , BINARY_FMT , ADD_CB , ADDb_HELP) ; + CommandIds[2] = registerCmd(REMOVE_CMD , UNARY_FMT , REMOVE_CB , REMOVE_HELP) ; + CommandIds[3] = registerCmd(DISABLE_CMD , UNARY_FMT , ENABLE_CB , DISABLEu_HELP) ; + CommandIds[4] = registerCmd(DISABLE_CMD , BINARY_FMT , ENABLE_CB , DISABLEb_HELP) ; + CommandIds[5] = registerCmd(ENABLE_CMD , UNARY_FMT , ENABLE_CB , ENABLEu_HELP) ; + CommandIds[6] = registerCmd(ENABLE_CMD , BINARY_FMT , ENABLE_CB , ENABLEb_HELP) ; + CommandIds[7] = registerCmd(ECHO_CMD , BINARY_FMT , ECHO_CB , ECHO_HELP) ; + CommandIds[8] = registerCmd(CHAT_CMD , BINARY_FMT , CHAT_CB , CHAT_HELP) ; + CommandIds[9] = registerCmd(BCAST_CMD , BINARY_FMT , BCAST_CB , BCAST_HELP) ; + CommandIds[10] = registerCmd(STATUS_CMD , UNARY_FMT , STATUS_CB , STATUSu_HELP) ; + CommandIds[11] = registerCmd(STATUS_CMD , BINARY_FMT , STATUS_CB , STATUSb_HELP) ; + CommandIds[12] = registerCmd(HELP_CMD , UNARY_FMT , HELP_CB , HELP_HELP) ; + + if (SentinelBridge) return TRUE ; else { alert(OOM_MSG) ; return FALSE ; } } -gboolean HandlePluginUnloaded(PurplePlugin *plugin) +gboolean handlePluginUnloaded(PurplePlugin* plugin) { int i ; for (i = 0 ; i < N_COMMANDS ; ++i) purple_cmd_unregister(CommandIds[i]) ; return TRUE ; } -void HandleIm(PurpleAccount* account , char* sender , char* buffer , +void handleIm(PurpleAccount* account , char* sender , char* buffer , PurpleConversation* conv , PurpleMessageFlags flags , void* data) { -DBGchat("received-chat-msg" , account , sender , conv , buffer , flags , data) ; +DBGchat("received-im-msg" , account , sender , conv , buffer , flags , data) ; // purple_conv_chat_send(PURPLE_CONV_CHAT(conv) , formatMessage()) ; } -void HandleChat(PurpleAccount* account , char* sender , char* buffer , +void handleChat(PurpleAccount* account , char* sender , char* buffer , PurpleConversation* conv , PurpleMessageFlags flags , void* data) { DBGchat("received-chat-msg" , account , sender , conv , buffer , flags , data) ; @@ -74,24 +207,34 @@ DBGchat("received-chat-msg" , account , sender , conv , buffer , flags , data) ; // purple_conv_chat_send(PURPLE_CONV_CHAT(conv) , formatMessage()) ; } -void HandleChannelClosed(PurpleConversation* conv , void* data) +void handleChannelClosed(PurpleConversation* conv , void* data) { DBGchannelClosed(conv) ; } -/* callbacks */ +/* admin command handlers */ -PurpleCmdRet HandleAddCmd(PurpleConversation* conv , const gchar* command , +PurpleCmdRet handleAddCmd(PurpleConversation* conv , const gchar* command , gchar** args , gchar** error , void* data) { + char* bridgeName ; Bridge* thisBridge ; + DBGcmd(command , args[0]) ; + bridgeName = (isBlank(args[0]))? DEFAULT_BRIDGE_NAME : args[0] ; + if ((thisBridge = getBridgeByChannel(conv)) != SentinelBridge) + { + if (thisBridge == getBridgeByName(bridgeName)) addExistsResp(conv , bridgeName) ; + else addConflictResp(conv) ; + } + else { setChannel(bridgeName , conv) ; storeSession() ; addResp(conv , bridgeName) ; } + return PURPLE_CMD_RET_OK ; } -PurpleCmdRet HandleRemoveCmd(PurpleConversation* conv , const gchar* command , +PurpleCmdRet handleRemoveCmd(PurpleConversation* conv , const gchar* command , gchar** args , gchar** error , void* data) { DBGcmd(command , args[0]) ; @@ -99,7 +242,7 @@ DBGcmd(command , args[0]) ; return PURPLE_CMD_RET_OK ; } -PurpleCmdRet HandleEnableCmd(PurpleConversation* conv , const gchar* command , +PurpleCmdRet handleEnableCmd(PurpleConversation* conv , const gchar* command , gchar** args , gchar** error , void* data) { DBGcmd(command , args[0]) ; @@ -107,7 +250,7 @@ DBGcmd(command , args[0]) ; return PURPLE_CMD_RET_OK ; } -PurpleCmdRet HandleEchoCmd(PurpleConversation* conv , const gchar* command , +PurpleCmdRet handleEchoCmd(PurpleConversation* conv , const gchar* command , gchar** args , gchar** error , void* data) { DBGcmd(command , args[0]) ; @@ -115,7 +258,7 @@ DBGcmd(command , args[0]) ; return PURPLE_CMD_RET_OK ; } -PurpleCmdRet HandleChatCmd(PurpleConversation* conv , const gchar* command , +PurpleCmdRet handleChatCmd(PurpleConversation* conv , const gchar* command , gchar** args , gchar** error , void* data) { DBGcmd(command , args[0]) ; @@ -123,7 +266,7 @@ DBGcmd(command , args[0]) ; return PURPLE_CMD_RET_OK ; } -PurpleCmdRet HandleBroadcastCmd(PurpleConversation* conv , const gchar* command , +PurpleCmdRet handleBroadcastCmd(PurpleConversation* conv , const gchar* command , gchar** args , gchar** error , void* data) { DBGcmd(command , args[0]) ; @@ -131,7 +274,7 @@ DBGcmd(command , args[0]) ; return PURPLE_CMD_RET_OK ; } -PurpleCmdRet HandleStatusCmd(PurpleConversation* conv , const gchar* command , +PurpleCmdRet handleStatusCmd(PurpleConversation* conv , const gchar* command , gchar** args , gchar** error , void* data) { DBGcmd(command , args[0]) ; @@ -139,7 +282,7 @@ DBGcmd(command , args[0]) ; return PURPLE_CMD_RET_OK ; } -PurpleCmdRet HandleHelpCmd(PurpleConversation* conv , const gchar* command , +PurpleCmdRet handleHelpCmd(PurpleConversation* conv , const gchar* command , gchar** args , gchar** error , void* data) { DBGcmd(command , args[0]) ; @@ -147,6 +290,158 @@ DBGcmd(command , args[0]) ; return PURPLE_CMD_RET_OK ; } +/* admin command responses */ + +void addResp(PurpleConversation* conv , char* bridgeName) +{ + chatBufferFillSS("%s '%s'" , CH_SET_MSG , bridgeName) ; + chatBufferDump(conv) ; bridgeStatsMsg(conv , bridgeName) ; +} + +void addExistsResp(PurpleConversation* conv , char* bridgeName) +{ + chatBufferFillSSS("%s %s '%s'" , THIS_CHANNEL_MSG , CHANNEL_EXISTS_MSG , bridgeName) ; + chatBufferDump(conv) ; +} + +void addConflictResp(PurpleConversation* conv) + { chatBufferFillS("%s" , BRIDGE_CONFLICT_MSG) ; chatBufferDump(conv) ; } +/* +function removeResp($bridgeName) +{ + global $CHANNEL_REMOVED_MSG , $BRIDGE_REMOVED_MSG ; $resp = $CHANNEL_REMOVED_MSG ; + + if (array_key_exists($bridgeName , $Bridges)) $resp .= bridgeStatsMsg($bridgeName) ; + else $resp .= $BRIDGE_REMOVED_MSG ; + return $resp ; +} + +function removeUnbridgedResp($accountId , $channelId) + { return channelStateMsg($accountId , $channelId) ; } + +function enableNoneResp($bridgeName) { return bridgeStatsMsg($bridgeName) ; } + +function enableAllResp($isEnable) +{ + global $ENABLING_ALL_MSG , $DISABLING_ALL_MSG ; + return ($isEnable)? $ENABLING_ALL_MSG : $DISABLING_ALL_MSG ; +} + +function enableResp($bridgeName , $enabledMsg) + { global $ENABLE_MSG ; return "$ENABLE_MSG '$bridgeName' $enabledMsg" ; } + +function echoResp($nick , $msg) + { global $NICK_PREFIX ; return chatOut($NICK_PREFIX , $nick , $msg) ; } + +function chatResp() { return "" ; } + +function chatUnbridgedResp($accountId , $channelId) + { return channelStateMsg($accountId , $channelId) ; } + +function broadcastResp($channels) +{ + global $BROADCAST_MSGa , $BROADCAST_MSGb ; + return $BROADCAST_MSGa . (nActiveChannels($channels) - 1) . $BROADCAST_MSGb ; +} + +function statusResp($accountId , $channelId , $bridgeName) +{ + global $Bridges ; + + $resp = channelStateMsg($accountId , $channelId) ; + if (!count($Bridges)) $resp .= "\n" . bridgeStatsMsg("") ; + else if ($bridgeName) $resp .= "\n" . bridgeStatsMsg($bridgeName) ; + else foreach ($Bridges as $name => $aBridge) $resp .= bridgeStatsMsg($name) ; + return $resp ; +} + +function helpResp() +{ + global $HELP_MSG , $HELP_MSGS ; $resp = $HELP_MSG ; + foreach ($HELP_MSGS as $trigger => $desc) $resp .= "\n$trigger\n\t=> $desc" ; + return $resp ; +} + +function exitResp() { global $EXIT_MSG ; return $EXIT_MSG ; } + +function defaultResp() +{ + global $UNKNOWN_MSG , $TRIGGER_PREFIX ; + return "$UNKNOWN_MSG '$TRIGGER_PREFIX$trigger'" ; +} +*/ +void bridgeStatsMsg(PurpleConversation* conv , char* bridgeName) +{ + Bridge* bridge ; Channel* channel ; unsigned int nChars ; + unsigned int nChannels ; char nchannels[5] ; char* activeMsg ; + +DBG("bridgeStatsMsg()") ; + + if ((bridge = getBridgeByName(bridgeName)) == SentinelBridge) + { + if (getNBridges()) chatBufferFillSS("\n%s '%s'" , NO_SUCH_BRIDGE_MSG , bridgeName) ; + else chatBufferFillS("\n%s" , NO_BRIDGES_MSG) ; + chatBufferDump(conv) ; return ; + } + + nChars = chatBufferFillSS("%s '%s' " , STATS_MSGa , bridgeName) ; + nChannels = getNChannels(bridge) ; + if (!nChannels) nChars += chatBufferCat(STATS_DELETED_MSG , nChars) ; + else + { + if (bridge->isEnabled) nChars += chatBufferCat(STATS_ENABLED_MSG , nChars) ; + else nChars += chatBufferCat(STATS_DISABLED_MSG , nChars) ; + snprintf(nchannels , 5 , " %d " , nChannels) ; nChars += 4 ; + nChars += chatBufferCat(nchannels , nChars) ; + nChars += chatBufferCat(STATS_MSGb , nChars) ; + } + + channel = bridge->sentinelChannel ; + while ((channel = channel->next)) + { + activeMsg = (channel->isActive)? CH_ACTIVE_MSG : CH_INACTIVE_MSG ; + nChars += chatBufferCat("\n" , nChars) ; + nChars += chatBufferCat(activeMsg , nChars) ; + nChars += chatBufferCat("'" , nChars) ; + nChars += chatBufferCat(channel->name , nChars) ; + nChars += chatBufferCat("' on '" , nChars) ; + nChars += chatBufferCat(channel->protocol , nChars) ; + nChars += chatBufferCat("' as '" , nChars) ; + nChars += chatBufferCat(channel->username , nChars) ; + nChars += chatBufferCat("'" , nChars) ; + } + chatBufferDump(conv) ; +} + +/* chat buffer helpers */ + +unsigned int chatBufferFillS( const char* fmt , const char* s1) + { return snprintf(ChatBuffer , CHAT_BUFFER_SIZE , fmt , s1) ; } + +unsigned int chatBufferFillSS( const char* fmt , const char* s1 , const char* s2) + { return snprintf(ChatBuffer , CHAT_BUFFER_SIZE , fmt , s1 , s2) ; } + +unsigned int chatBufferFillSSS( const char* fmt , const char* s1 , const char* s2 , + const char* s3) + { return snprintf(ChatBuffer , CHAT_BUFFER_SIZE , fmt , s1 , s2 , s3) ; } + +unsigned int chatBufferFillSSSDSD(const char* fmt , const char* s1 , const char* s2 , + const char* s3 , int d1 , const char* s4 , int d2) + { return snprintf(ChatBuffer , CHAT_BUFFER_SIZE , fmt , s1 , s2 , s3 , d1 , s4 , d2) ; } + +unsigned int chatBufferCat( const char* msg , unsigned int nChars) +{ + strncat(ChatBuffer , msg , CHAT_BUFFER_SIZE - nChars - 1) ; + return nChars + strlen(msg) ; +} + +void chatBufferDump(PurpleConversation* conv) +{ + purple_conversation_write(conv , BRIDGIN_NICK , ChatBuffer , + PURPLE_MESSAGE_SYSTEM , time(0)) ; +} + + /* main */ static PurplePluginInfo PluginInfo = @@ -158,4 +453,4 @@ static PurplePluginInfo PluginInfo = NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL } ; -PURPLE_INIT_PLUGIN(PLUGIN_NAME , HandlePluginInit , PluginInfo) +PURPLE_INIT_PLUGIN(PLUGIN_NAME , handlePluginInit , PluginInfo) diff --git a/bridgin.dbg.h b/bridgin.dbg.h index e044abd..6793c6b 100644 --- a/bridgin.dbg.h +++ b/bridgin.dbg.h @@ -1,21 +1,38 @@ #include "debug.h" -static void DBGchat(char* convType , PurpleAccount* account , char* sender , PurpleConversation* conv , char* buffer , PurpleMessageFlags flags , void* data) +// arges for DBG*() functions are in pairs<string , var> (DBGd implies "n=" , n) +static void DBG(const char* s1) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s\n" , s1) ; } + +static void DBGs(const char* s1 , const char* s2) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s%s\n" , s1 , s2) ; } + +static void DBGd(const char* s1 , int d1) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s%d\n" , s1 , d1) ; } + +static void DBGsd(const char* s1 , const char* s2 , const char* s3 , int d1) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s%s%s%d\n" , s1 , s2 , s3 , d1) ; } + +static void DBGss(const char* s1 , const char* s2 , const char* s3 , const char* s4) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s%s%s%s\n" , s1 , s2 , s3 , s4) ; } + +static void DBGsss(const char* s1 , const char* s2 , const char* s3 , const char* s4 , const char* s5 , const char* s6) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s%s%s%s%s%s\n" , s1 , s2 , s3 , s4 , s5 , s6) ; } + +static void DBGsdd(const char* s1 , const char* s2 , const char* s3 , int d1 , const char* s4 , int d2) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s%s%s%d%s%d\n" , s1 , s2 , s3 , d1 , s4 , d2) ; } + +static void DBGsssd(const char* s1 , const char* s2 , const char* s3 , const char* s4 , const char* s5 , const char* s6 , const char* s7 , int d1) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s%s%s%s%s%s%s%d\n" , s1 , s2 , s3 , s4 , s5 , s6 , s7 , d1) ; } + +static void DBGchat(char* convType , PurpleAccount* account , char* sender , PurpleConversation* conv , char* msg , PurpleMessageFlags flags , void* data) { - char dbg[64] ; + // call these from somewhere just to make the compiler stop barking when unused + DBG("") ; DBGs("" , "") ; DBGd("" , 0) ; DBGss("" , "" , "" , "") ; DBGsd("" , "" , "" , 0) ; + DBGsss("" , "" , "" , "" , "" , "") ; DBGsdd("" , "" , "" , 0 , "" , 0) ; + DBGsssd("" , "" , "" , "" , "" , "" , "" , 0) ; purple_debug_misc(PLUGIN_NAME , - "%s from %s\n\taccount = %d\n\tsender = %s\n\tchannel = %s (%d)\n\tmessage = %s\n\tflags = %d\n\tdata = %d\n" , + "%s from %s\n\taccount = %d\n\tsender = %s\n\tchannel = %s (%d)\n\tmessage = %s\n\tflags = %d\n\tdata = %d\n%s" , convType , sender , (int)account , sender , ((conv != NULL) ? purple_conversation_get_name(conv) : "(null)") , - (int)conv , buffer , flags , (int)data) ; - - sprintf(dbg , ((flags & PURPLE_MESSAGE_SEND)? "%s - loopback - dropping" : "%s") , convType) ; - SystemChat(conv , dbg) ; + (int)conv , msg , flags , (int)data , ((flags & PURPLE_MESSAGE_SEND)? "loopback - dropping" : "")) ; } static void DBGchannelClosed(PurpleConversation* conv) { purple_debug_misc(PLUGIN_NAME , "deleting-conversation (%s)\n" , purple_conversation_get_name(conv)) ; } -static void DBGcmd(const gchar* command , gchar* args) - { purple_debug_misc(PLUGIN_ID , "HandleCmd '/%s' args = %s\n" , command , args) ; } +static void DBGcmd(const char* command , char* args) + { purple_debug_misc(PLUGIN_NAME , "HandleCmd '/%s' args = %s\n" , command , args) ; } @@ -1,7 +1,7 @@ #define PURPLE_PLUGINS -// app constants +// plugin constants #define PLUGIN_TYPE PURPLE_PLUGIN_STANDARD #define PLUGIN_GUI_TYPE NULL #define PLUGIN_ID "core-mr-jonze-bridgin" @@ -11,9 +11,12 @@ #define PLUGIN_LONG_DESC "long description" #define PLUGIN_AUTHOR "bill auger <mr.j.spam.me@gmail.com>" #define PLUGIN_WEBSITE "https://github.com/bill-auger/bridgin" -#define PLUGIN_ONLOAD_CB HandlePluginLoaded -#define PLUGIN_ONUNLOAD_CB HandlePluginUnloaded -#define BRIDGIN_NICK "BRIDGIN" +#define PLUGIN_ONLOAD_CB handlePluginLoaded +#define PLUGIN_ONUNLOAD_CB handlePluginUnloaded + +// app constants +#define BRIDGIN_NICK "BRIDGIN" +#define DEFAULT_BRIDGE_NAME "default" // admin commands #define N_COMMANDS 13 @@ -22,36 +25,57 @@ #define ADD_CMD "add" #define ADDu_HELP "/ADD_CMD\nadd this channel to the default bridge" #define ADDb_HELP "/ADD_CMD 'a-bridge-name'\nadd this channel to the bridge 'a-bridge-name'" -#define ADD_CB HandleAddCmd +#define ADD_CB handleAddCmd #define REMOVE_CMD "rem" #define REMOVE_HELP "/REMOVE_CMD\nunbridge this channel" -#define REMOVE_CB HandleRemoveCmd +#define REMOVE_CB handleRemoveCmd #define DISABLE_CMD "disable" #define DISABLEu_HELP "/DISABLE_CMD\ntemporarily disable all bridges" #define DISABLEb_HELP "/DISABLE_CMD 'a-bridge-name'\ntemporarily disable the bridge 'a-bridge-name'" #define ENABLE_CMD "enable" #define ENABLEu_HELP "/ENABLE_CMD\nenable all bridges" #define ENABLEb_HELP "/ENABLE_CMD 'a-bridge-name'\nenable the bridge 'a-bridge-name'" -#define ENABLE_CB HandleEnableCmd +#define ENABLE_CB handleEnableCmd #define ECHO_CMD "echo" #define ECHO_HELP "/ECHO_CMD\necho text to the same channel" -#define ECHO_CB HandleEchoCmd +#define ECHO_CB handleEchoCmd #define CHAT_CMD "chat" #define CHAT_HELP "/CHAT_CMD\nrelay text to the all channels on this bridge" -#define CHAT_CB HandleChatCmd +#define CHAT_CB handleChatCmd #define BCAST_CMD "broadcast" #define BCAST_HELP "/BROADCAST_CMD\nrelay text to the all channels on all bridges as BRIDGIN_NICK" -#define BCAST_CB HandleBroadcastCmd +#define BCAST_CB handleBroadcastCmd #define STATUS_CMD "status" #define STATUSu_HELP "/STATUS_CMD\nshow status information for all bridges" #define STATUSb_HELP "/STATUS_CMD 'a-bridge-name'\nshow status information for the bridge 'a-bridge-name'" -#define STATUS_CB HandleStatusCmd +#define STATUS_CB handleStatusCmd #define HELP_CMD "help" #define HELP_HELP "/HELP_CMD\nshow avaiable admin commands" -#define HELP_CB HandleHelpCmd +#define HELP_CB handleHelpCmd +// admin command responses +#define CHAT_BUFFER_SIZE 8192 +#define CH_SET_MSG "channel set to bridge" +#define THIS_CHANNEL_MSG "this channel" +#define CHANNEL_EXISTS_MSG "already exists on bridge" +#define BRIDGE_CONFLICT_MSG "each channel may only be on one bridge" +#define NO_SUCH_BRIDGE_MSG "no such bridge" +#define NO_BRIDGES_MSG "no bridges exist" +#define STATS_MSGa "bridge" +#define STATS_DELETED_MSG "- deleted" +#define STATS_ENABLED_MSG "- enabled -" +#define STATS_DISABLED_MSG "- disabled -" +#define STATS_MSGb "channels bridged" +#define CH_ACTIVE_MSG " ( active ) " +#define CH_INACTIVE_MSG " (inactive) " +#define OOM_MSG "out of memory" -//#include <glib.h> +// model constants +#define PROTOCOL_BUFFER_SIZE 256 +#define IRC_PROTOCOL "IRC" + + +#include <string.h> #include "cmds.h" //#include "conversation.h" @@ -61,39 +85,94 @@ #include "version.h" -static PurplePluginInfo PluginInfo ; -static PurpleCmdId CommandIds[N_COMMANDS] ; +typedef struct Channel +{ + const char* name ; + char protocol[PROTOCOL_BUFFER_SIZE] ; + PurpleAccount* account ; + const char* username ; + PurpleConversation* conv ; + gboolean isActive ; + struct Channel* next ; +} Channel ; +typedef struct Bridge +{ + const char* name ; + gboolean isEnabled ; + Channel* sentinelChannel ; + struct Bridge* next ; +} Bridge ; + +static PurplePluginInfo PluginInfo ; +static PurplePlugin* ThisPlugin ; +static PurpleCmdId CommandIds[N_COMMANDS] ; +static char ChatBuffer[CHAT_BUFFER_SIZE] ; +static Bridge* SentinelBridge ; // helpers -static PurpleCmdId RegisterCmd(const char* command , const char* format , - PurpleCmdRet (* callback)() , const char* help) ; -static void SystemChat(PurpleConversation* conv , const char* msg) ; +PurpleCmdId registerCmd( const char* command , const char* format , + PurpleCmdRet (* callback)() , const char* help) ; +void alert( char* msg) ; +gboolean isBlank( const char* aCstring) ; + +// model helpers +Bridge* newBridge( char* bridgeName) ; +Channel* newChannel( PurpleConversation* conv) ; +Bridge* getBridgeByChannel(PurpleConversation* conv) ; +Bridge* getBridgeByName( char* bridgeName) ; +const char* getChannelName( PurpleConversation* conv) ; +const char* getProtocol( PurpleAccount *account) ; +PurpleAccount* getAccount( PurpleConversation* conv) ; +const char* getUsername( PurpleAccount *account) ; +const char* getNick( PurpleAccount *account) ; +void setChannel( char* bridgeName , PurpleConversation* conv) ; +void storeSession( void) ; +unsigned int getNBridges( void) ; +unsigned int getNChannels(Bridge* bridge) ; // event handlers -static void HandlePluginInit( PurplePlugin* plugin) ; -static gboolean HandlePluginLoaded( PurplePlugin* plugin) ; -static gboolean HandlePluginUnloaded(PurplePlugin* plugin) ; -static void HandleIm( PurpleAccount* account , char* sender , char* buffer , - PurpleConversation* conv , PurpleMessageFlags flags , void* data) ; -static void HandleChat(PurpleAccount* account , char* sender , char* buffer , - PurpleConversation* conv , PurpleMessageFlags flags , void* data) ; -static void HandleChannelClosed(PurpleConversation* conv, void *data) ; - -// callbacks -static PurpleCmdRet HandleAddCmd( PurpleConversation* conv , const gchar* cmd , - gchar** args , gchar** error , void* data) ; -static PurpleCmdRet HandleRemoveCmd( PurpleConversation* conv , const gchar* cmd , - gchar** args , gchar** error , void* data) ; -static PurpleCmdRet HandleEnableCmd( PurpleConversation* conv , const gchar* cmd , - gchar** args , gchar** error , void* data) ; -static PurpleCmdRet HandleEchoCmd( PurpleConversation* conv , const gchar* cmd , - gchar** args , gchar** error , void* data) ; -static PurpleCmdRet HandleChatCmd( PurpleConversation* conv , const gchar* cmd , - gchar** args , gchar** error , void* data) ; -static PurpleCmdRet HandleBroadcastCmd(PurpleConversation* conv , const gchar* cmd , - gchar** args , gchar** error , void* data) ; -static PurpleCmdRet HandleStatusCmd( PurpleConversation* conv , const gchar* cmd , - gchar** args , gchar** error , void* data) ; -static PurpleCmdRet HandleHelpCmd( PurpleConversation* conv , const gchar* cmd , - gchar** args , gchar** error , void* data) ; +void handlePluginInit( PurplePlugin* plugin) ; +gboolean handlePluginLoaded( PurplePlugin* plugin) ; +gboolean handlePluginUnloaded(PurplePlugin* plugin) ; +void handleIm( PurpleAccount* account , char* sender , + char* buffer , PurpleConversation* conv , + PurpleMessageFlags flags , void* data) ; +void handleChat( PurpleAccount* account , char* sender , + char* buffer , PurpleConversation* conv , + PurpleMessageFlags flags , void* data) ; +void handleChannelClosed( PurpleConversation* conv, void *data) ; + +// admin command handlers */ +PurpleCmdRet handleAddCmd( PurpleConversation* conv , const gchar* cmd , + gchar** args , gchar** error , void* data) ; +PurpleCmdRet handleRemoveCmd( PurpleConversation* conv , const gchar* cmd , + gchar** args , gchar** error , void* data) ; +PurpleCmdRet handleEnableCmd( PurpleConversation* conv , const gchar* cmd , + gchar** args , gchar** error , void* data) ; +PurpleCmdRet handleEchoCmd( PurpleConversation* conv , const gchar* cmd , + gchar** args , gchar** error , void* data) ; +PurpleCmdRet handleChatCmd( PurpleConversation* conv , const gchar* cmd , + gchar** args , gchar** error , void* data) ; +PurpleCmdRet handleBroadcastCmd(PurpleConversation* conv , const gchar* cmd , + gchar** args , gchar** error , void* data) ; +PurpleCmdRet handleStatusCmd( PurpleConversation* conv , const gchar* cmd , + gchar** args , gchar** error , void* data) ; +PurpleCmdRet handleHelpCmd( PurpleConversation* conv , const gchar* cmd , + gchar** args , gchar** error , void* data) ; + +// admin command responses +void chatBufferDump( PurpleConversation* conv) ; +void addResp( PurpleConversation* conv , char* bridgeName) ; +void addExistsResp( PurpleConversation* conv , char* bridgeName) ; +void addConflictResp(PurpleConversation* conv) ; +void bridgeStatsMsg( PurpleConversation* conv , char* bridgeName) ; + +// chat buffer helpers +unsigned int chatBufferFillS( const char* fmt , const char* s1) ; +unsigned int chatBufferFillSS( const char* fmt , const char* s1 , const char* s2) ; +unsigned int chatBufferFillSSS( const char* fmt , const char* s1 , const char* s2 , + const char* s3) ; +unsigned int chatBufferFillSSSDSD(const char* fmt , const char* s1 , const char* s2 , + const char* s3 , int d1 , const char* s4 , int d2) ; +unsigned int chatBufferCat( const char* msg , unsigned int nChars) ; @@ -0,0 +1,28 @@ +#!/bin/bash + +PLUGIN_OBJ=./bridgin.so +SUCCESS_MSG="compilation success" +FAILURE_MSG="compilation failure" +INSTALLING_MSG="installing to $HOME/.purple/plugins/" +NO_HOME_MSG='your $HOME environment var is not properly set'" - copy the file '$PLUGIN_OBJ' to YOUR_HOME_DIR/.purple/plugins/ or /usr/lib/purple-2/" +NOLAUNCH="nolaunch" +PIDGIN_BIN=`which pidgin` + + +make $PLUGIN_OBJ 1> /dev/null +if [ -f "$PLUGIN_OBJ" ] +then + if [ -d "$HOME" ] + then echo $(tput setaf 2)$SUCCESS_MSG" - "$INSTALLING_MSG + else echo $(tput setaf 2)$SUCCESS_MSG" - "$NO_HOME_MSG ; exit + fi +else echo $(tput setaf 1)$FAILURE_MSG ; exit +fi + +mv $PLUGIN_OBJ $HOME/.purple/plugins/ +if [ "$1" == $NOLAUNCH ] ; then exit ; fi ; + +if ((`pidof pidgin`)) ; then kill `pidof pidgin` ; fi ; + +if [ "$PIDGIN_BIN" == "" ] ; then PIDGIN_BIN=../../pidgin/pidgin ; fi ; +$PIDGIN_BIN & |