summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbill auger <mr.j.spam.me@gmail.com>2013-09-10 19:52:23 -0400
committerbill auger <mr.j.spam.me@gmail.com>2013-09-10 19:52:23 -0400
commitb70b43e1fe21766ed37c743b27c765ac9e216948 (patch)
tree044d168b6bf66395903402f7095c434049288ec9
parent2babc935b0c1f911689112e838dfd3a036c01142 (diff)
reimplement add command and status reporting
-rw-r--r--README.md57
-rw-r--r--bridgin.c375
-rw-r--r--bridgin.dbg.h35
-rw-r--r--bridgin.h167
-rwxr-xr-xinstall28
5 files changed, 568 insertions, 94 deletions
diff --git a/README.md b/README.md
index fe923d9..2c56780 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/bridgin.c b/bridgin.c
index d43da27..3fb3e13 100644
--- a/bridgin.c
+++ b/bridgin.c
@@ -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) ; }
diff --git a/bridgin.h b/bridgin.h
index 38c9fe9..9113f9b 100644
--- a/bridgin.h
+++ b/bridgin.h
@@ -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) ;
diff --git a/install b/install
new file mode 100755
index 0000000..4362653
--- /dev/null
+++ b/install
@@ -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 &