diff options
author | bill auger <mr.j.spam.me@gmail.com> | 2013-09-18 22:53:40 -0400 |
---|---|---|
committer | bill auger <mr.j.spam.me@gmail.com> | 2013-09-18 22:53:40 -0400 |
commit | 4102a2b3112c7e5ed9e75dad836e1d0dd59f6c1b (patch) | |
tree | 2aff6df21b4337302cb93ffdc70963a2a909c31b | |
parent | b107d6a1a737267623cf4a89b086525b7737ff6b (diff) |
reimplement persistence
-rw-r--r-- | CHANGELOG | 8 | ||||
-rw-r--r-- | README.md | 9 | ||||
-rw-r--r-- | bridgin.c | 543 | ||||
-rw-r--r-- | bridgin.dbg.h | 59 | ||||
-rw-r--r-- | bridgin.h | 172 |
5 files changed, 528 insertions, 263 deletions
@@ -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 @@ -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 @@ -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) ; } @@ -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) ; |