summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbill auger <mr.j.spam.me@gmail.com>2013-09-18 22:53:40 -0400
committerbill auger <mr.j.spam.me@gmail.com>2013-09-18 22:53:40 -0400
commit4102a2b3112c7e5ed9e75dad836e1d0dd59f6c1b (patch)
tree2aff6df21b4337302cb93ffdc70963a2a909c31b
parentb107d6a1a737267623cf4a89b086525b7737ff6b (diff)
reimplement persistence
-rw-r--r--CHANGELOG8
-rw-r--r--README.md9
-rw-r--r--bridgin.c543
-rw-r--r--bridgin.dbg.h59
-rw-r--r--bridgin.h172
5 files changed, 528 insertions, 263 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 52aecbe..ba2a178 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,11 +1,15 @@
bridgin changelog
+2013-09-18 - v0.5pre
+ CURRENT
+ reimplemented persistence via purple preferences prefs.xml
+
2013-09-11 - v0.5pre
- PENDING
+ b107d6a1a7
reimplemented chat relay
-2013-09-08 - v0.5pre
+2013-09-10 - v0.5pre
b70b43e1fe
reimplemented add channel command and status reporting
diff --git a/README.md b/README.md
index d82c683..3391f60 100644
--- a/README.md
+++ b/README.md
@@ -20,22 +20,23 @@ some new functionalities this will allow:
##build instructions for debian (ymmv)
-cd into your build dir and load sources and deps
+cd into your build dir and load the pidgin sources and build 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
+if you already have pidgin and/or finch installed
you can delete this build afterward
it is needed only to simplify building the bridgin plugin
+ cd ./pidgin*
./configure
- make all
+ make
now go make some C(__) and when the build has completed
copy the contents of this repo into ./libpurple/plugins
-cd into the plgins dir and run the install script
+cd into the plugins dir and run the install script
cd ./libpurple/plugins
chmod a+x ./install
diff --git a/bridgin.c b/bridgin.c
index 46fc73a..9b7bb33 100644
--- a/bridgin.c
+++ b/bridgin.c
@@ -1,9 +1,13 @@
+
+
+
+
#include "bridgin.h"
#include "bridgin.dbg.h"
-/* helpers */
+/* purple helpers */
PurpleCmdId registerCmd(const char* command , const char* format ,
PurpleCmdRet (* callback)() , const char* help)
@@ -12,6 +16,21 @@ PurpleCmdId registerCmd(const char* command , const char* format ,
PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_CHAT , PLUGIN_ID , callback , help , NULL) ;
}
+const char* getChannelName(PurpleConversation* aConv)
+ { return purple_conversation_get_name(aConv) ; }
+
+const char* getProtocol(PurpleAccount* anAccount)
+ { return purple_account_get_protocol_name(anAccount) ; }
+
+PurpleAccount* getAccount(PurpleConversation* aConv)
+ { return purple_conversation_get_account(aConv) ; }
+
+const char* getUsername(PurpleAccount* anAccount)
+ { return purple_account_get_username(anAccount) ; }
+
+const char* getNick(PurpleAccount* anAccount)
+ { return purple_account_get_name_for_display(anAccount) ; }
+
void alert(char* msg)
{
purple_notify_message(ThisPlugin , PURPLE_NOTIFY_MSG_INFO , msg ,
@@ -23,6 +42,12 @@ gboolean isBlank(const char* aCstring) { return (!aCstring || !*aCstring) ; }
/* model helpers */
+gboolean areReservedIds(char* bridgeName , char* channelUid)
+{
+ return (!strcmp(bridgeName , SENTINEL_NAME) ||
+ !strcmp(channelUid , SENTINEL_NAME)) ;
+}
+
Bridge* newBridge(char* bridgeName)
{
Bridge* aBridge ; Channel* aChannel ;
@@ -30,112 +55,112 @@ Bridge* newBridge(char* bridgeName)
aBridge = (Bridge*) malloc(sizeof(Bridge)) ; if (!aBridge) return NULL ;
aChannel = (Channel*)malloc(sizeof(Channel)) ; if (!aChannel) return NULL ;
- aBridge->name = bridgeName ;
+ strcpy(aBridge->name , bridgeName) ;
aBridge->isEnabled = TRUE ;
aBridge->next = NULL ;
aBridge->sentinelChannel = aChannel ;
- aChannel->name = "sentinel" ;
- aChannel->protocol[0] = '\0' ;
- aChannel->account = NULL ;
- aChannel->username = "" ;
- aChannel->conv = NULL ;
- aChannel->isActive = FALSE ;
- aChannel->next = NULL ;
+ strcpy(aChannel->uid , SENTINEL_NAME) ;
+ aChannel->next = NULL ;
return aBridge ;
}
-Channel* newChannel(PurpleConversation* aConv)
+Channel* newChannel()
{
- Channel* aChannel ; PurpleAccount* anAccount ;
- const char* protocol ; char* network ;
-
- aChannel = (Channel*)malloc(sizeof(Channel)) ; if (!aChannel) return NULL ;
+ Channel* aChannel = (Channel*)malloc(sizeof(Channel)) ; if (!aChannel) return NULL ;
- // append network url to protocol
- anAccount = getAccount(aConv) ; protocol = getProtocol(anAccount) ;
- if (!strcmp(protocol , IRC_PROTOCOL) && (network = strstr(getUsername(anAccount) , "@")))
- snprintf(aChannel->protocol , PROTOCOL_BUFFER_SIZE , "%s%s" , protocol , network) ;
- else strncpy(aChannel->protocol , protocol , PROTOCOL_BUFFER_SIZE) ;
-
- aChannel->name = getChannelName(aConv) ;
- aChannel->account = anAccount ;
- aChannel->username = getNick(anAccount) ;
- aChannel->conv = aConv ;
- aChannel->isActive = TRUE ;
- aChannel->next = NULL ;
+ strcpy(aChannel->uid , UidBuffer) ;
+ aChannel->next = NULL ;
return aChannel ;
}
-Bridge* getBridgeByChannel(PurpleConversation* aConv)
+void makeChannelId(PurpleConversation* aConv)
{
- Bridge* aBridge ; Channel* aChannel ;
+ PurpleAccount* anAccount ;
+ const char* protocol ; const char* username ; const char* channelName ;
- aBridge = SentinelBridge ;
- while (aBridge->next)
- {
- aChannel = (aBridge = aBridge->next)->sentinelChannel ;
- while (aChannel->next)
- if ((aChannel = aChannel->next)->conv == aConv)
-{
-DBGss("getBridgeByChannel() '" , getChannelName(aConv) , "' found" , "") ;
-
- return aBridge ;
+ anAccount = getAccount(aConv) ; protocol = getProtocol(anAccount) ;
+ username = getUsername(anAccount) ; channelName = getChannelName(aConv) ;
+ sprintf(UidBuffer , CHANNEL_ID_FMT , protocol , username , channelName) ;
}
- }
-DBGss("getBridgeByChannel() '" , getChannelName(aConv) , "' not found" , "") ;
- return SentinelBridge ;
-}
-
-Bridge* getBridgeByName(char* bridgeName)
+gboolean addChannel(char* bridgeName)
{
- Bridge* aBridge ;
+ Bridge* aBridge ; Channel* aChannel ;
+ char bridgePrefKey[UID_BUFFER_SIZE] ; char enabledPrefKey[UID_BUFFER_SIZE] ;
+ GList* channelsList = NULL ;
- aBridge = SentinelBridge ;
- while (aBridge->next)
- if (!strcmp((aBridge = aBridge->next)->name , bridgeName))
-{
-DBGss("getBridgeByName() '" , bridgeName , "' found" , "") ;
+DBGss("addChannel() bridgeName='" , bridgeName , "'" , "") ;
- return aBridge ;
-}
-DBGss("getBridgeByName() '" , bridgeName , "' not found" , "") ;
+ // bridge pref key
+ snprintf(bridgePrefKey , UID_BUFFER_SIZE , BRIDGE_PREF_FMT ,
+ BASE_PREF_KEY , bridgeName) ;
+ snprintf(enabledPrefKey , UID_BUFFER_SIZE , ENABLED_PREF_FMT ,
+ bridgePrefKey , ENABLED_PREF_KEY) ;
- return SentinelBridge ;
-}
+ if ((aBridge = getBridgeByName(bridgeName)) == SentinelBridge)
+ {
+ // create new bridge
+ while (aBridge->next) aBridge = aBridge->next ;
+ aBridge->next = newBridge(bridgeName) ;
+ if (!(aBridge = aBridge->next)) return FALSE ;
-const char* getChannelName(PurpleConversation* aConv) { return purple_conversation_get_name(aConv) ; }
+ // store bridge config
+ purple_prefs_add_bool(enabledPrefKey , TRUE) ;
+ purple_prefs_add_string_list(bridgePrefKey , channelsList) ;
-const char* getProtocol(PurpleAccount* anAccount) { return purple_account_get_protocol_name(anAccount) ; }
+DBGs("addChannel() adding new bridgeKey=" , bridgePrefKey) ;
+ }
+ else channelsList = purple_prefs_get_string_list(bridgePrefKey) ;
-PurpleAccount* getAccount(PurpleConversation* aConv) { return purple_conversation_get_account(aConv) ; }
+ // create new channel
+ aChannel = aBridge->sentinelChannel ;
+ while (aChannel->next) aChannel = aChannel->next ;
+ aChannel->next = newChannel() ;
+ if (!aChannel->next) { g_list_free(channelsList) ; return FALSE ; }
-const char* getUsername(PurpleAccount* anAccount) { return purple_account_get_username(anAccount) ; }
+ // store bridge config
+ channelsList = g_list_append(channelsList , (gpointer)UidBuffer) ;
+ purple_prefs_set_string_list(bridgePrefKey , channelsList) ;
-const char* getNick(PurpleAccount* anAccount) { return purple_account_get_name_for_display(anAccount) ; }
+DBGs("addChannel() adding new channelUid=" , UidBuffer) ;
-gboolean addChannel(char* bridgeName , PurpleConversation* aConv)
+ g_list_free(channelsList) ; return TRUE ;
+}
+
+Bridge* getBridgeByChannel(PurpleConversation* aConv)
{
Bridge* aBridge ; Channel* aChannel ;
- if ((aBridge = getBridgeByName(bridgeName)) == SentinelBridge)
+/*DBG*/makeChannelId(aConv);DBGss("getBridgeByChannel() channel='" , UidBuffer , "'" , "") ;
+
+ aBridge = SentinelBridge ; makeChannelId(aConv) ;
+ while ((aBridge = aBridge->next))
{
- while (aBridge->next) aBridge = aBridge->next ;
- aBridge->next = newBridge(bridgeName) ;
- if (aBridge->next) aBridge = aBridge->next ; else { alert(OOM_MSG) ; return FALSE ; }
+ aChannel = aBridge->sentinelChannel ;
+ while ((aChannel = aChannel->next))
+ if (!strcmp(aChannel->uid , UidBuffer))
+ return aBridge ;
}
- aChannel = aBridge->sentinelChannel ;
- while (aChannel->next) aChannel = aChannel->next ;
- aChannel->next = newChannel(aConv) ;
- if (!aChannel->next) { alert(OOM_MSG) ; return FALSE ; }
+DBGss("getBridgeByChannel() '" , UidBuffer , "' not found" , "") ;
- storeSession() ; return TRUE ;
+ return SentinelBridge ;
}
-void storeSession() {} // TODO:
+Bridge* getBridgeByName(const char* bridgeName)
+{
+ Bridge* aBridge = SentinelBridge ;
+
+ while ((aBridge = aBridge->next))
+ if (!strcmp(aBridge->name , bridgeName))
+ return aBridge ;
+
+DBGsd("getBridgeByName() '" , bridgeName , "' not found - nBridges=" , getNBridges()) ;
+
+ return SentinelBridge ;
+}
unsigned int getNBridges()
{
@@ -154,20 +179,21 @@ unsigned int getNChannels(Bridge* aBridge)
/* event handlers */
-void handlePluginInit(PurplePlugin* plugin)
- { ChatMutex = TRUE ; SentinelBridge = newBridge("sentinel") ; }
+void handlePluginInit(PurplePlugin* plugin) { purple_prefs_add_none(BASE_PREF_KEY) ; }
gboolean handlePluginLoaded(PurplePlugin* aPlugin)
{
- ThisPlugin = aPlugin ;
+ void* convs ;
+ GList* prefsList ; GList* prefsIter ; const char* prefKey ; char* bridgeName ;
+ GList* channelsList ; GList* channelsIter ;
- purple_signal_connect(purple_conversations_get_handle() , RECEIVED_IM_SIGNAL ,
- aPlugin , PURPLE_CALLBACK(handleChat) , NULL) ;
- purple_signal_connect(purple_conversations_get_handle() , RECEIVED_CHAT_SIGNAL ,
- aPlugin , PURPLE_CALLBACK(handleChat) , NULL) ;
- purple_signal_connect(purple_conversations_get_handle() , CHANNEL_CLOSING_SIGNAL ,
- aPlugin , PURPLE_CALLBACK(handleChannelClosed) , NULL) ;
+DBG("handlePluginLoaded()") ;
+ // init
+ ThisPlugin = aPlugin ; SentinelBridge = newBridge(SENTINEL_NAME) ;
+ if (!SentinelBridge) { alert(OOM_MSG) ; return FALSE ; }
+
+ // register admin commands
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) ;
@@ -182,42 +208,121 @@ gboolean handlePluginLoaded(PurplePlugin* aPlugin)
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 ; }
-}
+ // register conversation callbacks
+ convs = purple_conversations_get_handle() ;
+ purple_signal_connect(convs , RECEIVED_IM_SIGNAL , ThisPlugin ,
+ PURPLE_CALLBACK(handleChat) , NULL) ;
+ purple_signal_connect(convs , RECEIVED_CHAT_SIGNAL , ThisPlugin ,
+ PURPLE_CALLBACK(handleChat) , NULL) ;
+
+ // restore session
+ prefsList = purple_prefs_get_children_names(BASE_PREF_KEY) ;
+ prefsIter = g_list_first(prefsList) ;
+ while (prefsIter)
+ {
+if (purple_prefs_get_type((char*)prefsIter->data) == PURPLE_PREF_BOOLEAN)
+DBGsd("handlePluginLoaded() found bool prefKey=" , (char*)prefsIter->data , " val=" , purple_prefs_get_bool((char*)prefsIter->data)) ;
+else if (purple_prefs_get_type((char*)prefsIter->data) == PURPLE_PREF_STRING)
+DBGss("handlePluginLoaded() found string prefKey=" , (char*)prefsIter->data , " val=" , purple_prefs_get_string((char*)prefsIter->data)) ;
+
+ prefKey = (char*)prefsIter->data ;
+ if (purple_prefs_get_type(prefKey) == PURPLE_PREF_STRING_LIST &&
+ (bridgeName = strrchr(prefKey , '/')) && ++bridgeName)
+ {
+DBGs("handlePluginLoaded() found stored bridgeName=" , bridgeName) ;
+
+ channelsList = purple_prefs_get_string_list(prefKey) ;
+ channelsIter = g_list_first(channelsList) ;
+ while (channelsIter)
+ {
+DBGs("handlePluginLoaded() found stored channelUid=" , (char*)channelsIter->data) ;
+
+ strcpy(UidBuffer , (char*)channelsIter->data) ;
+ if (!addChannel(bridgeName))
+ {
+ g_list_free(channelsList) ; g_list_free(channelsIter) ;
+ g_list_free(prefsList) ; g_list_free(prefsIter) ;
+ alert(OOM_MSG) ; return FALSE ;
+ }
+
+ channelsIter = g_list_next(channelsIter) ;
+ }
+ g_list_free(channelsList) ; g_list_free(channelsIter) ;
+ }
+
+ prefsIter = g_list_next(prefsIter) ;
+ }
-gboolean handlePluginUnloaded(PurplePlugin* plugin)
-{
- int i ; for (i = 0 ; i < N_COMMANDS ; ++i) purple_cmd_unregister(CommandIds[i]) ;
+ g_list_foreach(prefsList , (GFunc)g_free , NULL) ;
+ g_list_free(prefsList) ; g_list_free(prefsIter) ;
return TRUE ;
}
-void handleChat(PurpleAccount* anAccount , char* sender , char* msg ,
- PurpleConversation* aConv , PurpleMessageFlags flags , void* data)
+gboolean handlePluginUnloaded(PurplePlugin* plugin)
{
- Bridge* aBridge ; unsigned int convType ; Channel* aChannel ;
+ unsigned int i ;
+ Bridge* prevBridge ; Bridge* nextBridge ;
+ Channel* prevChannel ; Channel* nextChannel ;
-DBGchat(((purple_conversation_get_type(aConv) == PURPLE_CONV_TYPE_IM)? RECEIVED_IM_SIGNAL : RECEIVED_CHAT_SIGNAL) , anAccount , sender , aConv , msg , flags , data) ;
+DBG("handlePluginUnloaded()") ;
- if (flags & PURPLE_MESSAGE_SEND) return ;
- if ((aBridge = getBridgeByChannel(aConv)) == SentinelBridge) return ;
+ // unregister commands
+ for (i = 0 ; i < N_COMMANDS ; ++i) purple_cmd_unregister(CommandIds[i]) ;
- chatBufferFillSSSS("%s %s%s %s" , NICK_PREFIX , sender , NICK_POSTFIX , msg) ;
- convType = purple_conversation_get_type(aConv) ;
- aChannel = aBridge->sentinelChannel ;
- while ((aChannel = aChannel->next)) if (aChannel->conv != aConv)
+ // unregister callbacks
+ purple_prefs_disconnect_by_handle(purple_prefs_get_handle()) ;
+ purple_signal_disconnect(purple_conversations_get_handle() , RECEIVED_IM_SIGNAL ,
+ ThisPlugin , PURPLE_CALLBACK(handleChat)) ;
+ purple_signal_disconnect(purple_conversations_get_handle() , RECEIVED_CHAT_SIGNAL ,
+ ThisPlugin , PURPLE_CALLBACK(handleChat)) ;
+
+ prevBridge = SentinelBridge ;
+ while ((nextBridge = prevBridge->next))
{
- if (convType == PURPLE_CONV_TYPE_IM)
- purple_conv_im_send(PURPLE_CONV_IM(aChannel->conv) , ChatBuffer) ;
- else if (convType == PURPLE_CONV_TYPE_CHAT)
- purple_conv_chat_send(PURPLE_CONV_CHAT(aChannel->conv) , ChatBuffer) ;
+ prevChannel = nextBridge->sentinelChannel ;
+ while ((nextChannel = prevChannel->next))
+ { free(prevChannel) ; prevChannel = nextChannel ; }
+ free(prevChannel) ; free(prevBridge) ; prevBridge = nextBridge ;
}
+ free(prevBridge) ;
+
+ return TRUE ;
}
-void handleChannelClosed(PurpleConversation* aConv , void* data)
+void handleChat(PurpleAccount* thisAccount , char* sender , char* msg ,
+ PurpleConversation* thisConv , PurpleMessageFlags flags , void* data)
{
-DBGchannelClosed(aConv) ;
+ GList* activeChannelsIter = NULL ;
+ Bridge* thisBridge ; PurpleConversation* aConv ; unsigned int convType ;
+// NOTE: DBGchat() should mirror changes to logic here
+DBGchat(((purple_conversation_get_type(thisConv) == PURPLE_CONV_TYPE_IM)? RECEIVED_IM_SIGNAL : RECEIVED_CHAT_SIGNAL) , thisAccount , sender , thisConv , msg , flags) ;
+
+ if (flags & PURPLE_MESSAGE_SEND) return ;
+ if (!(flags & PURPLE_MESSAGE_RECV)) return ;
+ if ((thisBridge = getBridgeByChannel(thisConv)) == SentinelBridge) return ;
+
+ chatBufferPutSSSS(CHAT_OUT_FMT , NICK_PREFIX , sender , NICK_POSTFIX , msg) ;
+
+ // relay chat to all opened channels on this bridge
+ activeChannelsIter = g_list_first(purple_get_conversations()) ;
+ while (activeChannelsIter)
+ {
+DBGs("handleChat() got active channelName=" , getChannelName((PurpleConversation*)activeChannelsIter->data)) ;
+
+ aConv = (PurpleConversation*)activeChannelsIter->data ;
+ if (aConv != thisConv && getBridgeByChannel(aConv) == thisBridge)
+ {
+ convType = purple_conversation_get_type(aConv) ;
+ if (convType == PURPLE_CONV_TYPE_IM)
+ purple_conv_im_send(purple_conversation_get_im_data(aConv) , ChatBuffer) ;
+ else if (convType == PURPLE_CONV_TYPE_CHAT)
+ purple_conv_chat_send(purple_conversation_get_chat_data(aConv) , ChatBuffer) ;
+ }
+
+ activeChannelsIter = g_list_next(activeChannelsIter) ;
+ }
}
@@ -226,21 +331,24 @@ DBGchannelClosed(aConv) ;
PurpleCmdRet handleAddCmd(PurpleConversation* aConv , const gchar* command ,
gchar** args , gchar** error , void* data)
{
- char* bridgeName ; Bridge* thisBridge ; unsigned int convType ;
+ char* bridgeName ; Bridge* thisBridge ;
DBGcmd(command , args[0]) ;
- convType = purple_conversation_get_type(aConv) ;
- if (convType != PURPLE_CONV_TYPE_IM && convType != PURPLE_CONV_TYPE_CHAT)
- return PURPLE_CMD_RET_OK ;
-
bridgeName = (isBlank(args[0]))? DEFAULT_BRIDGE_NAME : args[0] ;
if ((thisBridge = getBridgeByChannel(aConv)) != SentinelBridge)
{
if (thisBridge == getBridgeByName(bridgeName)) addExistsResp(aConv , bridgeName) ;
else addConflictResp(aConv) ;
}
- else if (addChannel(bridgeName , aConv)) addResp(aConv , bridgeName) ;
+ else
+ {
+ makeChannelId(aConv) ;
+ if (!areReservedIds(bridgeName , UidBuffer))
+ if (addChannel(bridgeName)) addResp(aConv , bridgeName) ;
+ else addFailResp(aConv) ;
+ else addReservedResp(aConv) ;
+ }
return PURPLE_CMD_RET_OK ;
}
@@ -290,7 +398,7 @@ PurpleCmdRet handleStatusCmd(PurpleConversation* aConv , const gchar* command ,
{
DBGcmd(command , args[0]) ;
- return PURPLE_CMD_RET_OK ;
+ statusResp(aConv , args[0]) ; return PURPLE_CMD_RET_OK ;
}
PurpleCmdRet handleHelpCmd(PurpleConversation* aConv , const gchar* command ,
@@ -305,21 +413,32 @@ DBGcmd(command , args[0]) ;
void addResp(PurpleConversation* aConv , char* bridgeName)
{
- chatBufferFillSS("%s '%s'" , CH_SET_MSG , bridgeName) ;
- chatBufferDump(aConv) ; bridgeStatsMsg(aConv , bridgeName) ;
+ chatBufferPutSS("%s '%s'" , CH_SET_MSG , bridgeName) ; chatBufferDump(aConv) ;
+ chatBufferInit() ; bridgeStatsMsg(bridgeName) ; chatBufferDump(aConv) ;
}
void addExistsResp(PurpleConversation* aConv , char* bridgeName)
{
- chatBufferFillSSS("%s %s '%s'" , THIS_CHANNEL_MSG , CHANNEL_EXISTS_MSG , bridgeName) ;
+ chatBufferPutSSS("%s %s '%s'" , THIS_CHANNEL_MSG , CHANNEL_EXISTS_MSG , bridgeName) ;
chatBufferDump(aConv) ;
}
void addConflictResp(PurpleConversation* aConv)
{
- chatBufferFillS("%s" , BRIDGE_CONFLICT_MSG) ; chatBufferDump(aConv) ;
+ chatBufferPutS("%s" , BRIDGE_CONFLICT_MSG) ; chatBufferDump(aConv) ;
+}
+
+void addReservedResp(PurpleConversation* aConv)
+{
+ chatBufferPutS("%s" , RESERVED_NAME_MSG) ; chatBufferDump(aConv) ;
}
-/*
+
+void addFailResp(PurpleConversation* aConv)
+{
+ chatBufferPutS("%s" , OOM_MSG) ; chatBufferDump(aConv) ;
+}
+
+/* TODO: the remaining admin commands and responses
function removeResp($bridgeName)
{
global $CHANNEL_REMOVED_MSG , $BRIDGE_REMOVED_MSG ; $resp = $CHANNEL_REMOVED_MSG ;
@@ -357,17 +476,6 @@ function broadcastResp($channels)
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 ;
@@ -383,77 +491,171 @@ function defaultResp()
return "$UNKNOWN_MSG '$TRIGGER_PREFIX$trigger'" ;
}
*/
-void bridgeStatsMsg(PurpleConversation* aConv , char* bridgeName)
+
+void statusResp(PurpleConversation* aConv , char* bridgeName)
{
- Bridge* aBridge ; Channel* aChannel ; unsigned int nChars ;
- unsigned int nChannels ; char nchannels[5] ; char* activeMsg ;
+ Bridge* aBridge ; unsigned int nBridges = getNBridges() ;
-DBG("bridgeStatsMsg()") ;
+DBGs("statusResp() bridgeName=" , (!nBridges)? "no bridges" : ((!isBlank(bridgeName))? bridgeName : "unspecified - listing all")) ;
- if ((aBridge = getBridgeByName(bridgeName)) == SentinelBridge)
+ if (!nBridges) { chatBufferInit() ; bridgeStatsMsg("") ; }
+ else if (!isBlank(bridgeName)) { chatBufferInit() ; bridgeStatsMsg(bridgeName) ; }
+ else
{
- if (getNBridges()) chatBufferFillSS("\n%s '%s'" , NO_SUCH_BRIDGE_MSG , bridgeName) ;
- else chatBufferFillS("\n%s" , NO_BRIDGES_MSG) ;
- chatBufferDump(aConv) ; return ;
+ chatBufferPutSDS("%s %d %s\n\n" , STATS_MSGa , getNBridges() , STATS_MSGb) ;
+
+ aBridge = SentinelBridge ;
+ while ((aBridge = aBridge->next)) bridgeStatsMsg(aBridge->name) ;
}
+ if (nBridges) channelStateMsg(aConv) ;
+ chatBufferDump(aConv) ;
+}
+
+void channelStateMsg(PurpleConversation* aConv)
+{
+// NOTE: callers of channelStateMsg() should first initialize ChatBuffer
+// then eventually call chatBufferDump() to flush to screen
+
+ Bridge* aBridge ;
+
+DBGs("statusResp() channelName=" , getChannelName(aConv)) ;
+
+ if ((aBridge = getBridgeByChannel(aConv)) != SentinelBridge)
+ {
+ uidBufferPutSSS("%s %s '%s'" , THIS_CHANNEL_MSG , THIS_BRIDGE_MSG , aBridge->name) ;
+ chatBufferCat(UidBuffer) ;
+ }
+ else
+ {
+ uidBufferPutSS("%s %s" , THIS_CHANNEL_MSG , UNBRIDGED_MSG) ;
+ chatBufferCat(UidBuffer) ;
+ }
+}
+
+void bridgeStatsMsg(const char* bridgeName)
+{
+// NOTE: callers of bridgeStatsMsg() should first initialize ChatBuffer
+// then eventually call chatBufferDump() to flush to screen
+
+ gboolean doesBridgeExist ; Bridge* aBridge ; Channel* aChannel ;
+ unsigned int nChannels ;
+ GList* activeChannelsIter = NULL ; gboolean isActive = FALSE ;
+ char* activeMsg ; char* protocol ; char* username ; const char* channelName ;
+ char* network ; char nick[UID_BUFFER_SIZE] ;
+
+DBG("bridgeStatsMsg()") ;
+
+ aBridge = getBridgeByName(bridgeName) ;
+ doesBridgeExist = (aBridge != SentinelBridge) ;
+ if (!doesBridgeExist)
+ if (!getNBridges()) statusBufferPutS("%s" , NO_BRIDGES_MSG) ;
+ else statusBufferPutSS("%s '%s'" , NO_SUCH_BRIDGE_MSG , bridgeName) ;
+ else statusBufferPutSS("%s '%s' - " , STATS_MSGc , bridgeName) ;
+ chatBufferCat(StatusBuffer) ; if (!doesBridgeExist) return ;
- nChars = chatBufferFillSS("%s '%s' " , STATS_MSGa , bridgeName) ;
nChannels = getNChannels(aBridge) ;
- if (!nChannels) nChars += chatBufferCat(STATS_DELETED_MSG , nChars) ;
+ if (!nChannels) chatBufferCat(STATS_DELETED_MSG) ;
else
{
- if (aBridge->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) ;
+ if (aBridge->isEnabled) chatBufferCat(STATS_ENABLED_MSG) ;
+ else chatBufferCat(STATS_DISABLED_MSG) ;
+ statusBufferPutDS(" - %d %s\n" , nChannels , STATS_MSGd) ;
+ chatBufferCat(StatusBuffer) ;
}
aChannel = aBridge->sentinelChannel ;
while ((aChannel = aChannel->next))
{
- activeMsg = (aChannel->isActive)? CH_ACTIVE_MSG : CH_INACTIVE_MSG ;
- nChars += chatBufferCat("\n" , nChars) ;
- nChars += chatBufferCat(activeMsg , nChars) ;
- nChars += chatBufferCat("'" , nChars) ;
- nChars += chatBufferCat(aChannel->name , nChars) ;
- nChars += chatBufferCat("' on '" , nChars) ;
- nChars += chatBufferCat(aChannel->protocol , nChars) ;
- nChars += chatBufferCat("' as '" , nChars) ;
- nChars += chatBufferCat(aChannel->username , nChars) ;
- nChars += chatBufferCat("'" , nChars) ;
- }
- chatBufferDump(aConv) ;
+ // determine if bridged aChannel is opened or closed
+ activeChannelsIter = g_list_first(purple_get_conversations()) ;
+ while (activeChannelsIter)
+ {
+if (aBridge == SentinelBridge->next && aChannel == aBridge->sentinelChannel->next)
+DBGs("bridgeStatsMsg() got active channelName=" , getChannelName((PurpleConversation*)activeChannelsIter->data)) ;
+
+ makeChannelId((PurpleConversation*)activeChannelsIter->data) ;
+ isActive |= !strcmp(aChannel->uid , UidBuffer) ;
+ activeChannelsIter = g_list_next(activeChannelsIter) ;
+ }
+ activeMsg = (isActive)? CH_ACTIVE_MSG : CH_INACTIVE_MSG ;
+
+DBGss("bridgeStatsMsg() aChannel=" , aChannel->uid , " " , activeMsg) ;
+
+ // parse channel data from channelUid
+ uidBufferPutS("%s" , aChannel->uid) ;
+ if (!(protocol = strtok(UidBuffer , UID_DELIMITER)) ||
+ !(username = strtok(NULL , UID_DELIMITER)) ||
+ !(channelName = strtok(NULL , UID_DELIMITER)))
+ continue ;
+
+DBGsssss("bridgeStatsMsg() parsed channelId " , activeMsg , " protocol='" , protocol , "' username='" , username , "' channelName='" , channelName , "'" , "") ;
+
+ // display channel data
+ statusBufferPutSSS(" %s '%s' on '%s" , activeMsg , channelName , protocol) ;
+ chatBufferCat(StatusBuffer) ;
+ if (!strcmp(protocol , IRC_PROTOCOL) &&
+ (network = strchr(username , '@')) &&
+ (strncpy(nick , username , network - username)))
+ {
+ nick[network - username] = '\0' ;
+ statusBufferPutSS("%s' as '%s'\n" , network , nick) ;
+ }
+ else statusBufferPutS("' as '%s'\n" , username) ;
+ chatBufferCat(StatusBuffer) ;
+ } // each aChannel
+
+ chatBufferCat("\n") ;
}
-/* chat buffer helpers */
-unsigned int chatBufferFillS( const char* fmt , const char* s1)
- { return snprintf(ChatBuffer , CHAT_BUFFER_SIZE , fmt , s1) ; }
+/* text buffer helpers */
-unsigned int chatBufferFillSS( const char* fmt , const char* s1 , const char* s2)
- { return snprintf(ChatBuffer , CHAT_BUFFER_SIZE , fmt , s1 , s2) ; }
+void uidBufferPutS( const char* fmt , const char* s1)
+ { snprintf(UidBuffer , UID_BUFFER_SIZE , fmt , s1) ; }
-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) ; }
+void uidBufferPutSS( const char* fmt , const char* s1 , const char* s2)
+ { snprintf(UidBuffer , UID_BUFFER_SIZE , fmt , s1 , s2) ; }
-unsigned int chatBufferFillSSSS( const char* fmt , const char* s1 , const char* s2 ,
- const char* s3 , const char* s4)
- { return snprintf(ChatBuffer , CHAT_BUFFER_SIZE , fmt , s1 , s2 , s3 , s4) ; }
+void uidBufferPutSSS( const char* fmt , const char* s1 , const char* s2 , const char* s3)
+ { snprintf(UidBuffer , UID_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) ; }
+void statusBufferPutS( const char* fmt , const char* s1)
+ { snprintf(StatusBuffer , UID_BUFFER_SIZE , fmt , s1) ; }
-unsigned int chatBufferCat( const char* msg , unsigned int nChars)
-{
- strncat(ChatBuffer , msg , CHAT_BUFFER_SIZE - nChars - 1) ;
- return nChars + strlen(msg) ;
-}
+void statusBufferPutSS( const char* fmt , const char* s1 , const char* s2)
+ { snprintf(StatusBuffer , UID_BUFFER_SIZE , fmt , s1 , s2) ; }
+
+void statusBufferPutDS( const char* fmt , int d1 , const char* s1)
+ { snprintf(StatusBuffer , UID_BUFFER_SIZE , fmt , d1 , s1) ; }
+
+void statusBufferPutSSS(const char* fmt , const char* s1 , const char* s2 , const char* s3)
+ { snprintf(StatusBuffer , UID_BUFFER_SIZE , fmt , s1 , s2 , s3) ; }
+
+void chatBufferInit() { ChatBuffer[0] = '\0' ; }
+
+void chatBufferPutS( const char* fmt , const char* s1)
+ { snprintf(ChatBuffer , CHAT_BUFFER_SIZE , fmt , s1) ; }
+
+void chatBufferPutSS( const char* fmt , const char* s1 , const char* s2)
+ { snprintf(ChatBuffer , CHAT_BUFFER_SIZE , fmt , s1 , s2) ; }
+
+void chatBufferPutSSS( const char* fmt , const char* s1 , const char* s2 , const char* s3)
+ { snprintf(ChatBuffer , CHAT_BUFFER_SIZE , fmt , s1 , s2 , s3) ; }
+
+void chatBufferPutSDS( const char* fmt , const char* s1 , int d1 , const char* s2)
+ { snprintf(ChatBuffer , CHAT_BUFFER_SIZE , fmt , s1 , d1 , s2) ; }
+
+void chatBufferPutSSSS( const char* fmt , const char* s1 , const char* s2 ,
+ const char* s3 , const char* s4)
+ { snprintf(ChatBuffer , CHAT_BUFFER_SIZE , fmt , s1 , s2 , s3 , s4) ; }
+
+void chatBufferCat( const char* aCstring)
+ { strncat(ChatBuffer , aCstring , CHAT_BUFFER_SIZE - strlen(ChatBuffer) - 1) ; }
void chatBufferDump(PurpleConversation* aConv)
{
+DBGs("chatBufferDump() ChatBuffer\n=" , ChatBuffer) ;
+
purple_conversation_write(aConv , BRIDGIN_NICK , ChatBuffer ,
PURPLE_MESSAGE_SYSTEM , time(0)) ;
}
@@ -470,4 +672,5 @@ static PurplePluginInfo PluginInfo =
NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL
} ;
+
PURPLE_INIT_PLUGIN(PLUGIN_NAME , handlePluginInit , PluginInfo)
diff --git a/bridgin.dbg.h b/bridgin.dbg.h
index b675c93..9fb7901 100644
--- a/bridgin.dbg.h
+++ b/bridgin.dbg.h
@@ -6,33 +6,64 @@ static void DBG(const char* s1) { if (isBlank(s1)) return ; purple_debug_misc(PL
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 DBGd(const char* s1 , int d1) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s%d\n" , s1 , 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 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 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 DBGdd(const char* s1 , int d1 , const char* s2 , int d2) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s%d%s%d\n" , s1 , d1 , s2 , d2) ; }
-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 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 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 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 DBGchat(char* convType , PurpleAccount* anAccount , char* sender , PurpleConversation* aConv , char* msg , PurpleMessageFlags flags , void* data)
+//static void DBGddd(const char* s1 , int d1 , const char* s2 , int d2 , const char* s3 , int d3) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s%d%s%d%s%d\n" , s1 , d1 , s2 , d2 , s3 , d3) ; }
+
+//static void DBGssss(const char* s1 , const char* s2 , const char* s3 , const char* s4 , const char* s5 , const char* s6 , const char* s7 , const char* s8) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s%s%s%s%s%s%s%s\n" , s1 , s2 , s3 , s4 , s5 , s6 , s7 , s8) ; }
+
+//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 DBGsdsd(const char* s1 , const char* s2 , const char* s3 , int d1 , const char* s4 , const char* s5 , const char* s6 , int d2) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s%s%s%d%s%s%s%d\n" , s1 , s2 , s3 , d1 , s4 , s5 , s6 , d2) ; }
+
+static void DBGsssss(const char* s1 , const char* s2 , const char* s3 , const char* s4 , const char* s5 , const char* s6 , const char* s7 , const char* s8 , const char* s9 , const char* s10) { if (isBlank(s1)) return ; purple_debug_misc(PLUGIN_NAME , "%s%s%s%s%s%s%s%s%s%s\n" , s1 , s2 , s3 , s4 , s5 , s6 , s7 , s8 , s9 , s10) ; }
+
+static void DBGchat(char* convType , PurpleAccount* thisAccount , char* sender ,
+ PurpleConversation* thisConv , char* msg , PurpleMessageFlags flags)
{
- // 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) ;
+ Bridge* thisBridge = getBridgeByChannel(thisConv) ;
+ const char* channelName = purple_conversation_get_name(thisConv) ;
+ gboolean isLocal = (flags & PURPLE_MESSAGE_SEND) ;
+ gboolean isRemote = (flags & PURPLE_MESSAGE_RECV) ;
+ gboolean isUnbridged = (thisBridge == SentinelBridge) ;
+ GList* activeChannelsIter = g_list_first(purple_get_conversations()) ;
+ unsigned int nChannels = 0 ; PurpleConversation* aConv ;
+ while (activeChannelsIter)
+ {
+ aConv = (PurpleConversation*)activeChannelsIter->data ;
+ if (aConv != thisConv && getBridgeByChannel(aConv) == thisBridge)
+ ++nChannels ;
+
+ activeChannelsIter = g_list_next(activeChannelsIter) ;
+ }
+ statusBufferPutDS("%d %s" , nChannels , "channels") ;
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" ,
- convType , sender , (int)anAccount , sender , ((aConv != NULL) ? purple_conversation_get_name(aConv) : "(null)") ,
- (int)aConv , msg , flags , (int)data , ((flags & PURPLE_MESSAGE_SEND)? "loopback - dropping" : "")) ;
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%d%s%s%s\n" ,
+ convType , ((isLocal)? " from admin " : " from user ") , sender ,
+ "\n\taccount = " , getProtocol(thisAccount) , " as " , getUsername(thisAccount) ,
+ "\n\tsender = " , sender ,
+ "\n\tchannel = " , ((!thisConv) ? "(null)" : channelName) ,
+ "\n\tmessage = " , msg ,
+ "\n\tflags = " , flags ,
+ "\n" , ((isLocal)? "local message - dropping" :
+ ((!isRemote)? "special message - dropping" :
+ ((isUnbridged)? "unbridged - dropping" : "relaying to "))) ,
+ ((isRemote && !isUnbridged)? StatusBuffer : "")) ;
}
-static void DBGchannelClosed(PurpleConversation* aConv)
- { purple_debug_misc(PLUGIN_NAME , "deleting-conversation (%s)\n" , purple_conversation_get_name(aConv)) ; }
+// static void DBGchannelClosed(PurpleConversation* thisConv)
+// { purple_debug_misc(PLUGIN_NAME , "deleting-conversation (%s)\n" , purple_conversation_get_name(thisConv)) ; }
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 5d952c7..c1bf646 100644
--- a/bridgin.h
+++ b/bridgin.h
@@ -1,5 +1,11 @@
-#define PURPLE_PLUGINS
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef PURPLE_PLUGINS
+# define PURPLE_PLUGINS
+#endif
// plugin constants
#define PLUGIN_TYPE PURPLE_PLUGIN_STANDARD
@@ -17,9 +23,26 @@
// app constants
#define BRIDGIN_NICK "BRIDGIN"
#define DEFAULT_BRIDGE_NAME "default"
-#define NICK_PREFIX "(from" // dont use '<' some clients will supress it as html
+#define CHAT_OUT_FMT "%s %s%s %s"
+#define NICK_PREFIX "(from" // dont use '<' - some clients will supress it as html
#define NICK_POSTFIX ")"
+// model constants
+#define BRIDGE_PREF_FMT "%s/%s"
+#define ENABLED_PREF_FMT "%s%s"
+#define BASE_PREF_KEY "/plugins/core/"PLUGIN_NAME
+#define BASE_PREF_LABEL PLUGIN_NAME" preferences"
+#define ENABLED_PREF_KEY "-enabled"
+#define SENTINEL_NAME "sentinel"
+#define UID_BUFFER_SIZE 256
+#define UID_DELIMITER "::"
+#define CHANNEL_ID_FMT "%s"UID_DELIMITER"%s"UID_DELIMITER"%s"
+
+// purple constants
+#define RECEIVED_IM_SIGNAL "received-im-msg"
+#define RECEIVED_CHAT_SIGNAL "received-chat-msg"
+#define IRC_PROTOCOL "IRC"
+
// admin commands
#define N_COMMANDS 13
#define BINARY_FMT "s"
@@ -28,7 +51,7 @@
#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 REMOVE_CMD "rem"
+#define REMOVE_CMD "remove"
#define REMOVE_HELP "/REMOVE_CMD\nunbridge this channel"
#define REMOVE_CB handleRemoveCmd
#define DISABLE_CMD "disable"
@@ -45,7 +68,7 @@
#define CHAT_HELP "/CHAT_CMD\nrelay text to the all channels on this bridge"
#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_HELP "/BCAST_CMD\nrelay text to the all channels on all bridges as BRIDGIN_NICK"
#define BCAST_CB handleBroadcastCmd
#define STATUS_CMD "status"
#define STATUSu_HELP "/STATUS_CMD\nshow status information for all bridges"
@@ -61,26 +84,22 @@
#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 RESERVED_NAME_MSG "invalid name - not adding"
+#define THIS_BRIDGE_MSG "is on bridge"
+#define UNBRIDGED_MSG "is not bridged"
#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 STATS_MSGa "status:"
+#define STATS_MSGb "bridges defined"
+#define STATS_MSGc "bridge"
+#define STATS_DELETED_MSG "deleted"
+#define STATS_ENABLED_MSG "enabled"
+#define STATS_DISABLED_MSG "disabled"
+#define STATS_MSGd "channels bridged"
+#define CH_ACTIVE_MSG "( active )"
+#define CH_INACTIVE_MSG "(inactive)"
#define OOM_MSG "out of memory"
-// model constants
-#define PROTOCOL_BUFFER_SIZE 256
-#define IRC_PROTOCOL "IRC"
-
-// purple constants
-#define RECEIVED_IM_SIGNAL "received-im-msg"
-#define RECEIVED_CHAT_SIGNAL "received-chat-msg"
-#define CHANNEL_CLOSING_SIGNAL "deleting-conversation"
-
#include <string.h>
@@ -94,62 +113,56 @@
typedef struct Channel
{
- const char* name ;
- char protocol[PROTOCOL_BUFFER_SIZE] ;
- PurpleAccount* account ;
- const char* username ;
- PurpleConversation* conv ;
- gboolean isActive ;
- struct Channel* next ;
+ char uid[UID_BUFFER_SIZE] ;
+ struct Channel* next ;
} Channel ;
typedef struct Bridge
{
- const char* name ;
+ char name[UID_BUFFER_SIZE] ;
gboolean isEnabled ;
Channel* sentinelChannel ;
struct Bridge* next ;
} Bridge ;
-static PurplePluginInfo PluginInfo ; // init pre main()
-static PurplePlugin* ThisPlugin ; // init on handlePluginLoaded()
-static PurpleCmdId CommandIds[N_COMMANDS] ; // init on handlePluginLoaded()
-static char ChatBuffer[CHAT_BUFFER_SIZE] ;
-static gboolean ChatMutex ; // init on handlePluginInit()
-static Bridge* SentinelBridge ; // init on handlePluginInit()
-
-// helpers
-PurpleCmdId registerCmd( const char* command , const char* format ,
- PurpleCmdRet (*callback)() , const char* help) ;
-void alert( char* msg) ;
-gboolean isBlank( const char* aCstring) ;
+static PurplePluginInfo PluginInfo ; // init pre main()
+static PurplePlugin* ThisPlugin ; // init handlePluginLoaded()
+static PurpleCmdId CommandIds[N_COMMANDS] ; // init handlePluginLoaded()
+static Bridge* SentinelBridge ; // init handlePluginInit()
+static char UidBuffer[UID_BUFFER_SIZE] ; // volatile
+static char StatusBuffer[UID_BUFFER_SIZE] ; // volatile
+static char ChatBuffer[CHAT_BUFFER_SIZE] ; // volatile
+
+// purple helpers
+PurpleCmdId registerCmd( const char* command , const char* format ,
+ PurpleCmdRet (*callback)() , const char* help) ;
+const char* getChannelName(PurpleConversation* aConv) ;
+const char* getProtocol( PurpleAccount* anAccount) ;
+PurpleAccount* getAccount( PurpleConversation* aConv) ;
+const char* getUsername( PurpleAccount* anAccount) ;
+const char* getNick( PurpleAccount* anAccount) ;
+void alert( char* msg) ;
+gboolean isBlank( const char* aCstring) ;
// model helpers
-Bridge* newBridge( char* bridgeName) ;
-Channel* newChannel( PurpleConversation* aConv) ;
-Bridge* getBridgeByChannel(PurpleConversation* aConv) ;
-Bridge* getBridgeByName( char* bridgeName) ;
-const char* getChannelName( PurpleConversation* aConv) ;
-const char* getProtocol( PurpleAccount* anAccount) ;
-PurpleAccount* getAccount( PurpleConversation* aConv) ;
-const char* getUsername( PurpleAccount* anAccount) ;
-const char* getNick( PurpleAccount* anAccount) ;
-gboolean addChannel( char* bridgeName , PurpleConversation* aConv) ;
-void storeSession( void) ;
-unsigned int getNBridges( void) ;
-unsigned int getNChannels(Bridge* aBridge) ;
+gboolean areReservedIds( char* bridgeName , char* channelUid) ;
+gboolean isReservedId( char* aCstring) ;
+Bridge* newBridge( char* bridgeName) ;
+Channel* newChannel( void) ;
+void makeChannelId( PurpleConversation* aConv) ;
+gboolean addChannel( char* bridgeName) ;
+Bridge* getBridgeByChannel(PurpleConversation* aConv) ;
+Bridge* getBridgeByName( const char* bridgeName) ;
+unsigned int getNBridges( void) ;
+unsigned int getNChannels( Bridge* aBridge) ;
// event handlers
void handlePluginInit( PurplePlugin* plugin) ;
gboolean handlePluginLoaded( PurplePlugin* plugin) ;
gboolean handlePluginUnloaded(PurplePlugin* plugin) ;
-void handleIm( PurpleAccount* anAccount , char* sender ,
- char* buffer , PurpleConversation* aConv ,
- PurpleMessageFlags flags , void* data) ;
void handleChat( PurpleAccount* anAccount , char* sender ,
char* buffer , PurpleConversation* aConv ,
PurpleMessageFlags flags , void* data) ;
-void handleChannelClosed( PurpleConversation* aConv, void *data) ;
// admin command handlers */
PurpleCmdRet handleAddCmd( PurpleConversation* aConv , const gchar* cmd ,
@@ -170,19 +183,32 @@ PurpleCmdRet handleHelpCmd( PurpleConversation* aConv , const gchar* cmd ,
gchar** args , gchar** error , void* data) ;
// admin command responses
-void chatBufferDump( PurpleConversation* aConv) ;
-void addResp( PurpleConversation* aConv , char* bridgeName) ;
-void addExistsResp( PurpleConversation* aConv , char* bridgeName) ;
-void addConflictResp(PurpleConversation* aConv) ;
-void bridgeStatsMsg( PurpleConversation* aConv , 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 chatBufferFillSSSS( const char* fmt , const char* s1 , const char* s2 ,
- const char* s3 , const char* s4) ;
-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) ;
+// NOTE: callers of channelStateMsg() or bridgeStatsMsg()
+// should first initialize ChatBuffer using one of the text buffer helpers
+// then eventually call chatBufferDump() to flush to screen
+void chatBufferDump( PurpleConversation* aConv) ;
+void addResp( PurpleConversation* aConv , char* bridgeName) ;
+void addExistsResp( PurpleConversation* aConv , char* bridgeName) ;
+void addConflictResp(PurpleConversation* aConv) ;
+void addReservedResp(PurpleConversation* aConv) ;
+void addFailResp( PurpleConversation* aConv) ;
+void statusResp( PurpleConversation* aConv , char* bridgeName) ;
+void channelStateMsg(PurpleConversation* aConv) ;
+void bridgeStatsMsg( const char* bridgeName) ;
+
+// text buffer helpers
+void uidBufferPutS( const char* fmt , const char* s1) ;
+void uidBufferPutSS( const char* fmt , const char* s1 , const char* s2) ;
+void uidBufferPutSSS( const char* fmt , const char* s1 , const char* s2 , const char* s3) ;
+void statusBufferPutS( const char* fmt , const char* s1) ;
+void statusBufferPutSS( const char* fmt , const char* s1 , const char* s2) ;
+void statusBufferPutDS( const char* fmt , int d1 , const char* s1) ;
+void statusBufferPutSSS(const char* fmt , const char* s1 , const char* s2 , const char* s3) ;
+void chatBufferInit( void) ;
+void chatBufferPutS( const char* fmt , const char* s1) ;
+void chatBufferPutSS( const char* fmt , const char* s1 , const char* s2) ;
+void chatBufferPutSSS( const char* fmt , const char* s1 , const char* s2 , const char* s3) ;
+void chatBufferPutSDS( const char* fmt , const char* s1 , int d1 , const char* s2) ;
+void chatBufferPutSSSS( const char* fmt , const char* s1 , const char* s2 ,
+ const char* s3 , const char* s4) ;
+void chatBufferCat( const char* msg) ;