123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854 |
- /*\
- |*| This file is part of the Bridgin program
- |*| Copyright 2013-2014 bill-auger <https://github.com/bill-auger/bridgin/issues>
- |*|
- |*| Bridgin is free software: you can redistribute it and/or modify
- |*| it under the terms of the GNU Affero General Public License as published by
- |*| the Free Software Foundation, either version 3 of the License, or
- |*| (at your option) any later version.
- |*|
- |*| Bridgin is distributed in the hope that it will be useful,
- |*| but WITHOUT ANY WARRANTY; without even the implied warranty of
- |*| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- |*| GNU Affero General Public License for more details.
- |*|
- |*| You should have received a copy of the GNU Affero General Public License
- |*| along with Bridgin. If not, see <http://www.gnu.org/licenses/>.
- \*/
- #include "bridgin.h"
- #include "bridgin.dbg.h"
- /* globals */
- static char* Commands[N_UNIQ_CMDS] = COMMANDS ;
- static unsigned int NRelayChannels = 0 ;
- static PurplePluginInfo PluginInfo =
- {
- PURPLE_PLUGIN_MAGIC , PURPLE_MAJOR_VERSION , PURPLE_MINOR_VERSION ,
- PLUGIN_TYPE , PLUGIN_GUI_TYPE , 0 , NULL , PURPLE_PRIORITY_DEFAULT ,
- PLUGIN_ID , PLUGIN_NAME , PLUGIN_VERSION , PLUGIN_SHORT_DESC , PLUGIN_LONG_DESC ,
- PLUGIN_AUTHOR , PLUGIN_WEBSITE , PLUGIN_ONLOAD_CB , PLUGIN_ONUNLOAD_CB ,
- NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL , NULL
- } ;
- /* purple helpers */
- 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 registerCommands()
- {
- 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 , DISABLE_CB , DISABLEu_HELP) ;
- CommandIds[4] = registerCmd(DISABLE_CMD , BINARY_FMT , DISABLE_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) ;
- }
- void registerCallbacks()
- {
- void* convs = purple_conversations_get_handle() ;
- purple_signal_connect(convs , RECEIVING_IM_SIGNAL , ThisPlugin ,
- PURPLE_CALLBACK(CHAT_RECV_CB) , NULL) ;
- purple_signal_connect(convs , RECEIVING_CHAT_SIGNAL , ThisPlugin ,
- PURPLE_CALLBACK(CHAT_RECV_CB) , NULL) ;
- }
- void unregisterCommands()
- {
- unsigned int i ;
- for (i = 0 ; i < N_COMMANDS ; ++i) purple_cmd_unregister(CommandIds[i]) ;
- }
- void unregisterCallbacks()
- {
- purple_prefs_disconnect_by_handle(purple_prefs_get_handle()) ;
- purple_signal_disconnect(purple_conversations_get_handle() , RECEIVING_IM_SIGNAL ,
- ThisPlugin , PURPLE_CALLBACK(CHAT_RECV_CB)) ;
- purple_signal_disconnect(purple_conversations_get_handle() , RECEIVING_CHAT_SIGNAL ,
- ThisPlugin , PURPLE_CALLBACK(CHAT_RECV_CB)) ;
- }
- 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(PurpleConversation* aConv)
- { return purple_account_get_name_for_display(getAccount(aConv)) ; }
- /* model helpers */
- void prepareBridgeKeys(const char* bridgeName)
- {
- snprintf(BridgeKeyBuffer , SM_BUFFER_SIZE , BRIDGE_PREF_FMT ,
- BASE_PREF_KEY , bridgeName) ;
- snprintf(EnabledKeyBuffer , SM_BUFFER_SIZE , ENABLED_PREF_FMT ,
- BridgeKeyBuffer , ENABLED_PREF_KEY) ;
- }
- void prepareChannelUid(PurpleConversation* aConv)
- {
- PurpleAccount* anAccount ;
- const char* protocol ; const char* username ; const char* channelName ;
- anAccount = getAccount(aConv) ; protocol = getProtocol(anAccount) ;
- username = getUsername(anAccount) ; channelName = getChannelName(aConv) ;
- sprintf(ChannelUidBuffer , CHANNEL_UID_FMT , protocol , username , channelName) ;
- }
- gint isMatch(gconstpointer a , gconstpointer b) { return strcmp((char*)a , (char*)b) ; }
- void prefKey2Name(const char* prefKey , char* nameBuffer)
- { snprintf(nameBuffer , SM_BUFFER_SIZE , "%s" , strrchr(prefKey , '/') + 1) ; }
- void getBridgeName(PurpleConversation* aConv , char* bridgeNameBuffer)
- {
- GList* prefsList ; GList* prefsIter ; char* prefKey ; GList* channelsList ;
- // search for this channelUid
- prepareChannelUid(aConv) ; bridgeNameBuffer[0] = '\0' ;
- prefsList = purple_prefs_get_children_names(BASE_PREF_KEY) ;
- prefsIter = g_list_first(prefsList) ;
- while (prefsIter)
- {
- #if DEBUG_LOGIC
- if (purple_prefs_get_type((char*)prefsIter->data) == PURPLE_PREF_STRING_LIST)
- DBGss("getBridgeName() found stored bridgeName='" , strrchr((char*)prefsIter->data , '/') + 1 , "'" , "") ;
- #endif
- #if DEBUG_VB
- else if (purple_prefs_get_type((char*)prefsIter->data) == PURPLE_PREF_BOOLEAN)
- DBGsds("getBridgeName() 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)
- DBGsss("getBridgeName() found string prefKey='" , (char*)prefsIter->data , "' val='" , purple_prefs_get_string((char*)prefsIter->data) , "'" , "") ;
- #endif
- prefKey = (char*)prefsIter->data ;
- if (!isChannelsPref(prefKey)) { prefsIter = g_list_next(prefsIter) ; continue ; }
- // set bridgeNameBuffer to channelUid if found
- channelsList = purple_prefs_get_string_list(prefKey) ;
- if (g_list_find_custom(channelsList , ChannelUidBuffer , (GCompareFunc)isMatch))
- prefKey2Name(prefKey , bridgeNameBuffer) ;
- #if DEBUG_LOGIC
- if (g_list_find_custom(channelsList , ChannelUidBuffer , (GCompareFunc)isMatch))
- DBGsss("getBridgeName() found channel=" , ChannelUidBuffer , "' on bridgeName='" , bridgeNameBuffer , "'" , "") ;
- #endif
- #if DEBUG_VB
- else DBGsss("getBridgeName() not found channel='" , ChannelUidBuffer , "' on bridgeName='" , bridgeNameBuffer , "'" , "") ;
- #endif
- prefsIter = g_list_next(prefsIter) ;
- }
- g_list_foreach(prefsList , (GFunc)g_free , NULL) ;
- g_list_free(prefsIter) ; g_list_free(prefsList) ;
- }
- unsigned int getNBridges()
- {
- GList* prefsList ; unsigned int nBridges ;
- prefsList = purple_prefs_get_children_names(BASE_PREF_KEY) ;
- nBridges = g_list_length(prefsList) / 2 ;
- g_list_foreach(prefsList , (GFunc)g_free , NULL) ;
- g_list_free(prefsList) ;
- return nBridges ;
- }
- unsigned int getNChannels(const char* bridgePrefKey)
- {
- GList* channelsList ; unsigned int nChannels ;
- channelsList = purple_prefs_get_string_list(bridgePrefKey) ;
- nChannels = g_list_length(channelsList) ;
- return nChannels ;
- }
- void getNRelayChannels(char* bridgePrefKey , PurpleConversation* thisConv)
- {
- // NOTE: thisConv will be excluded from the count - pass in NULL to include it
- GList* activeChannelsIter ; PurpleConversation* aConv ;
- char thisBridgeName[SM_BUFFER_SIZE] ; char aBridgeName[SM_BUFFER_SIZE] ;
- prefKey2Name(bridgePrefKey , thisBridgeName) ;
- if (!isChannelsPref(bridgePrefKey)) return ;
- activeChannelsIter = g_list_first(purple_get_conversations()) ;
- while (activeChannelsIter)
- {
- aConv = (PurpleConversation*)activeChannelsIter->data ;
- getBridgeName(aConv , aBridgeName) ;
- if (aConv != thisConv && !strcmp(aBridgeName , thisBridgeName)) ++NRelayChannels ;
- activeChannelsIter = g_list_next(activeChannelsIter) ;
- }
- }
- gboolean isChannelsPref(const char* bridgePrefKey)
- {
- return (purple_prefs_exists(bridgePrefKey) &&
- purple_prefs_get_type(bridgePrefKey) == PURPLE_PREF_STRING_LIST) ;
- }
- gboolean doesBridgeExist(const char* bridgeName)
- { prepareBridgeKeys(bridgeName) ; return isChannelsPref(BridgeKeyBuffer) ; }
- gboolean isBridgeEnabled(const char* bridgeName)
- {
- prepareBridgeKeys(bridgeName) ;
- return purple_prefs_exists(EnabledKeyBuffer) &&
- purple_prefs_get_bool(EnabledKeyBuffer) ;
- }
- gboolean isChannelBridged(PurpleConversation* aConv)
- {
- char thisBridgeName[SM_BUFFER_SIZE] ; getBridgeName(aConv , thisBridgeName) ;
- return !isBlank(thisBridgeName) ;
- }
- gboolean areReservedIds(char* bridgeName , char* channelUid , const char* channelName)
- {
- return (!strcmp(bridgeName , "") || // TODO: better validations?
- !strcmp(channelUid , "") ||
- !strcmp(channelName , "NickServ") ||
- !strcmp(channelName , "MemoServ")) ;
- }
- void createChannel(char* bridgeName)
- {
- GList* channelsList = NULL ;
- #if DEBUG_VB
- DBGss("createChannel() bridgeName='" , bridgeName , "'" , "") ;
- #endif
- prepareBridgeKeys(bridgeName) ;
- // add bridge to store if necessary
- if (!doesBridgeExist(bridgeName))
- {
- purple_prefs_add_bool(EnabledKeyBuffer , TRUE) ;
- purple_prefs_add_string_list(BridgeKeyBuffer , channelsList) ;
- #if DEBUG_LOGIC
- DBGss("createChannel() added new bridgeKey='" , BridgeKeyBuffer , "'" , "") ;
- #endif
- }
- // add channel to store
- channelsList = purple_prefs_get_string_list(BridgeKeyBuffer) ;
- channelsList = g_list_prepend(channelsList , (gpointer)ChannelUidBuffer) ;
- purple_prefs_set_string_list(BridgeKeyBuffer , channelsList) ;
- #if DEBUG_LOGIC
- DBGss("createChannel() added new channelUid='" , ChannelUidBuffer , "'" , "") ;
- #endif
- }
- void destroyChannel(PurpleConversation* aConv)
- {
- GList* channelsList = NULL ; GList* channelsIter = NULL ;
- char thisBridgeName[SM_BUFFER_SIZE] ; getBridgeName(aConv , thisBridgeName) ;
- // remove channel from store
- prepareBridgeKeys(thisBridgeName) ; prepareChannelUid(aConv) ;
- channelsList = purple_prefs_get_string_list(BridgeKeyBuffer) ;
- channelsIter = g_list_first(channelsList) ;
- while (channelsIter)
- if (!strcmp(channelsIter->data , ChannelUidBuffer))
- {
- channelsList = g_list_delete_link(channelsList , channelsIter) ;
- channelsIter = g_list_first(channelsList) ;
- }
- else channelsIter = g_list_next(channelsIter) ;
- purple_prefs_set_string_list(BridgeKeyBuffer , channelsList) ;
- #if DEBUG_LOGIC
- DBGssss("destroyChannel() removed channel='" , getChannelName(aConv) , "' from bridge='" , thisBridgeName , ((getNChannels(BridgeKeyBuffer))? "" : "' also removing bridge='") , ((getNChannels(BridgeKeyBuffer))? "" : thisBridgeName) , "'" , "") ;
- #endif
- if (getNChannels(BridgeKeyBuffer)) return ;
- // remove empty bridge from store
- purple_prefs_remove(BridgeKeyBuffer) ; purple_prefs_remove(EnabledKeyBuffer) ;
- }
- void enableBridge(char* bridgeName , gboolean shouldEnable)
- {
- prepareBridgeKeys(bridgeName) ;
- if (purple_prefs_get_bool(EnabledKeyBuffer) == shouldEnable) return ;
- purple_prefs_set_bool(EnabledKeyBuffer , shouldEnable) ;
- }
- void enableBridgeEach(char* bridgePrefKey , gboolean* shouldEnable)
- {
- char bridgeName[SM_BUFFER_SIZE] ; prefKey2Name(bridgePrefKey , bridgeName) ;
- if (isChannelsPref(bridgePrefKey)) enableBridge(bridgeName , *shouldEnable) ;
- }
- /* event handlers */
- void handlePluginInit(PurplePlugin* aPlugin)
- { ThisPlugin = aPlugin ; purple_prefs_add_none(BASE_PREF_KEY) ; }
- gboolean handlePluginLoaded(PurplePlugin* aPlugin)
- {
- #if DEBUG_EVS
- DBG("handlePluginLoaded()") ;
- #endif
- registerCommands() ; registerCallbacks() ; chatBufferClear() ; return TRUE ;
- }
- gboolean handlePluginUnloaded(PurplePlugin* plugin)
- {
- #if DEBUG_EVS
- DBG("handlePluginUnloaded()") ;
- #endif
- unregisterCommands() ; unregisterCallbacks() ; return TRUE ;
- }
- gboolean handleChat(PurpleAccount* thisAccount , char** sender , char** msg ,
- PurpleConversation* thisConv , PurpleMessageFlags* flags , void* data)
- {
- char thisBridgeName[SM_BUFFER_SIZE] ;
- if (!thisConv) return TRUE ; // supress rogue msgs (autojoined server msgs maybe unbound)
- getBridgeName(thisConv , thisBridgeName) ;
- #if DEBUG_CHAT // NOTE: DBGchat() should mirror changes to logic here
- DBGchat(thisAccount , *sender , thisConv , *msg , *flags , thisBridgeName) ;
- #endif
- if (!isBridgeEnabled(thisBridgeName)) return FALSE ; // input channel bridge is disabled
- if (*flags & PURPLE_MESSAGE_SEND) return FALSE ; // never relay unprefixed local chat
- if (!(*flags & PURPLE_MESSAGE_RECV)) return FALSE ; // TODO: handle special message types
- prepareRelayChat(NICK_PREFIX , *sender , *msg) ;
- relayMessage(thisBridgeName , thisConv) ; chatBufferClear() ;
- return FALSE ;
- }
- /* admin command handlers */
- PurpleCmdRet handleAddCmd(PurpleConversation* thisConv , const gchar* command ,
- gchar** args , gchar** error , void* data)
- {
- char thisBridgeName[SM_BUFFER_SIZE] ; char* thatBridgeName ;
- #if DEBUG_EVS
- DBGcmd(command , *args) ;
- #endif
- thatBridgeName = (isBlank(*args))? DEFAULT_BRIDGE_NAME : *args ;
- if (isChannelBridged(thisConv))
- {
- getBridgeName(thisConv , thisBridgeName) ;
- if (strcmp(thisBridgeName , thatBridgeName)) addConflictResp(thisConv) ;
- else addExistsResp(thisConv , thisBridgeName) ;
- }
- else
- {
- prepareChannelUid(thisConv) ;
- if (!areReservedIds(thatBridgeName , ChannelUidBuffer , getChannelName(thisConv)))
- { createChannel(thatBridgeName) ; addResp(thisConv , thatBridgeName) ; }
- else addReservedResp(thisConv) ;
- }
- return PURPLE_CMD_RET_OK ;
- }
- PurpleCmdRet handleRemoveCmd(PurpleConversation* thisConv , const gchar* command ,
- gchar** args , gchar** error , void* data)
- {
- char thisBridgeName[SM_BUFFER_SIZE] ; getBridgeName(thisConv , thisBridgeName) ;
- #if DEBUG_EVS
- DBGcmd(command , *args) ;
- #endif
- if (isBlank(thisBridgeName)) removeUnbridgedResp(thisConv) ;
- else { destroyChannel(thisConv) ; removeResp(thisConv , thisBridgeName) ; }
- return PURPLE_CMD_RET_OK ;
- }
- PurpleCmdRet handleEnableCmd(PurpleConversation* thisConv , const gchar* command ,
- gchar** args , gchar** error , void* data)
- {
- gboolean shouldEnable ; char* bridgeName ; GList* prefsList ;
- #if DEBUG_EVS
- DBGcmd(command , *args) ;
- #endif
- shouldEnable = !strcmp(command , ENABLE_CMD) ; bridgeName = *args ;
- if (!getNBridges()) enableNoneResp(thisConv , "") ;
- else if (isBlank(bridgeName))
- {
- enableAllResp(thisConv , shouldEnable) ;
- prefsList = purple_prefs_get_children_names(BASE_PREF_KEY) ;
- g_list_foreach(prefsList , (GFunc)enableBridgeEach , &shouldEnable) ;
- g_list_foreach(prefsList , (GFunc)enableRespEach , thisConv) ;
- g_list_foreach(prefsList , (GFunc)g_free , NULL) ;
- g_list_free(prefsList) ;
- }
- else if (doesBridgeExist(bridgeName))
- {
- enableBridge(bridgeName , shouldEnable) ;
- enableResp(thisConv , bridgeName , shouldEnable) ;
- }
- else enableNoneResp(thisConv , bridgeName) ;
- return PURPLE_CMD_RET_OK ;
- }
- PurpleCmdRet handleEchoCmd(PurpleConversation* thisConv , const gchar* command ,
- gchar** args , gchar** error , void* data)
- {
- #if DEBUG_EVS
- DBGcmd(command , *args) ;
- #endif
- adminEcho(thisConv , *args) ; return PURPLE_CMD_RET_OK ;
- }
- PurpleCmdRet handleChatCmd(PurpleConversation* thisConv , const gchar* command ,
- gchar** args , gchar** error , void* data)
- {
- char thisBridgeName[SM_BUFFER_SIZE] ; getBridgeName(thisConv , thisBridgeName) ;
- #if DEBUG_EVS
- DBGcmd(command , *args) ;
- #endif
- if (isChannelBridged(thisConv)) adminChat(thisConv , *args , thisBridgeName) ;
- else { channelStateMsg(thisConv) ; chatBufferDump(thisConv) ; }
- return PURPLE_CMD_RET_OK ;
- }
- PurpleCmdRet handleBroadcastCmd(PurpleConversation* thisConv , const gchar* command ,
- gchar** args , gchar** error , void* data)
- {
- #if DEBUG_EVS
- DBGcmd(command , *args) ;
- #endif
- broadcastResp(thisConv) ; adminBroadcast(thisConv , *args) ; return PURPLE_CMD_RET_OK ;
- }
- PurpleCmdRet handleStatusCmd(PurpleConversation* thisConv , const gchar* command ,
- gchar** args , gchar** error , void* data)
- {
- #if DEBUG_EVS
- DBGcmd(command , *args) ;
- #endif
- statusResp(thisConv , *args) ; return PURPLE_CMD_RET_OK ;
- }
- PurpleCmdRet handleHelpCmd(PurpleConversation* thisConv , const gchar* command ,
- gchar** args , gchar** error , void* data)
- {
- #if DEBUG_EVS
- DBGcmd(command , *args) ;
- #endif
- helpResp(thisConv) ; return PURPLE_CMD_RET_OK ;
- }
- /* admin command responses */
- void addResp(PurpleConversation* thisConv , char* thisBridgeName)
- {
- chatBufferPutSS("%s '%s'\n" , CH_SET_MSG , thisBridgeName) ;
- bridgeStatsMsg(thisBridgeName) ; chatBufferDump(thisConv) ;
- }
- void addExistsResp(PurpleConversation* thisConv , char* thisBridgeName)
- {
- chatBufferPutSSS("%s %s '%s'" , THIS_CHANNEL_MSG , CHANNEL_EXISTS_MSG , thisBridgeName) ;
- chatBufferDump(thisConv) ;
- }
- void addConflictResp(PurpleConversation* thisConv)
- { chatBufferPut(BRIDGE_CONFLICT_MSG) ; chatBufferDump(thisConv) ; }
- void addReservedResp(PurpleConversation* thisConv)
- { chatBufferPut(RESERVED_NAME_MSG) ; chatBufferDump(thisConv) ; }
- void addFailResp(PurpleConversation* thisConv)
- { chatBufferPut(OOM_MSG) ; chatBufferDump(thisConv) ; }
- void removeResp(PurpleConversation* thisConv , char* thisBridgeName)
- {
- chatBufferPutSS("%s '%s'" , CHANNEL_REMOVED_MSG , thisBridgeName) ;
- if (doesBridgeExist(thisBridgeName))
- { chatBufferCat("\n") ; bridgeStatsMsg(thisBridgeName) ; }
- else { chatBufferCatSSSS("\n'" , thisBridgeName , "' " , BRIDGE_REMOVED_MSG) ; }
- chatBufferDump(thisConv) ;
- }
- void removeUnbridgedResp(PurpleConversation* thisConv)
- { channelStateMsg(thisConv) ; chatBufferDump(thisConv) ; }
- void enableNoneResp(PurpleConversation* thisConv , char* bridgeName)
- { bridgeStatsMsg(bridgeName) ; chatBufferDump(thisConv) ; }
- void enableAllResp(PurpleConversation* thisConv , gboolean shouldEnable)
- {
- chatBufferPut(((shouldEnable)? ENABLING_ALL_MSG : DISABLING_ALL_MSG)) ;
- chatBufferDump(thisConv) ;
- }
- void enableResp(PurpleConversation* thisConv , char* bridgeName , gboolean shouldEnable)
- {
- char* enabledMsg = ((shouldEnable)? ENABLED_MSG : DISABLED_MSG) ;
- chatBufferPutSSS("%s '%s' %s" , ENABLE_MSG , bridgeName , enabledMsg) ;
- chatBufferDump(thisConv) ;
- }
- void enableRespEach(char* bridgePrefKey , PurpleConversation* thisConv)
- {
- char bridgeName[SM_BUFFER_SIZE] ; prefKey2Name(bridgePrefKey , bridgeName) ;
- if (isChannelsPref(bridgePrefKey))
- enableResp(thisConv , bridgeName , isBridgeEnabled(bridgeName)) ;
- }
- void adminEcho(PurpleConversation* thisConv , char* msg)
- {
- prepareRelayChat(NICK_PREFIX , getNick(thisConv) , msg) ; chatBufferDump(thisConv) ;
- }
- void adminChat(PurpleConversation* thisConv , char* msg , char* thisBridgeName)
- {
- prepareRelayChat(NICK_PREFIX , getNick(thisConv) , msg) ;
- relayMessage(thisBridgeName , NULL) ; chatBufferClear() ;
- }
- void adminBroadcast(PurpleConversation* thisConv , char* msg)
- {
- GList* prefsList ;
- prepareRelayChat(BCAST_PREFIX , getNick(thisConv) , msg) ;
- prefsList = purple_prefs_get_children_names(BASE_PREF_KEY) ;
- g_list_foreach(prefsList , (GFunc)relayMessageEach , NULL) ;
- g_list_foreach(prefsList , (GFunc)g_free , NULL) ;
- g_list_free(prefsList) ; chatBufferClear() ;
- }
- void broadcastResp(PurpleConversation* thisConv)
- {
- GList* prefsList ; NRelayChannels = 0 ;
- prefsList = purple_prefs_get_children_names(BASE_PREF_KEY) ;
- g_list_foreach(prefsList , (GFunc)getNRelayChannels , NULL) ;
- g_list_foreach(prefsList , (GFunc)g_free , NULL) ;
- g_list_free(prefsList) ;
- if (!NRelayChannels) chatBufferPut(NO_BRIDGES_MSG) ;
- else chatBufferPutSDS("%s %d %s" , BROADCAST_MSGa , NRelayChannels , BROADCAST_MSGb) ;
- chatBufferDump(thisConv) ;
- }
- void statusResp(PurpleConversation* thisConv , char* bridgeName)
- {
- unsigned int nBridges ; GList* prefsList ;
- #if DEBUG_VB
- if (!getNBridges()) DBG("statusResp() no bridges") ; else if (isBlank(bridgeName)) DBG("statusResp() bridge unspecified - listing all") ; else DBGss("statusResp() bridgeName='" , bridgeName , "'" , "") ;
- #endif
- nBridges = getNBridges() ;
- chatBufferPutSDS("%s %d %s" , STATS_MSGa , nBridges , STATS_MSGb) ;
- if (nBridges) chatBufferCat("\n") ; else { chatBufferDump(thisConv) ; return ; }
- if (!isBlank(bridgeName)) { bridgeStatsMsg(bridgeName) ; chatBufferCat("\n") ; }
- else
- {
- prefsList = purple_prefs_get_children_names(BASE_PREF_KEY) ;
- g_list_foreach(prefsList , (GFunc)bridgeStatsMsgEach , NULL) ;
- g_list_foreach(prefsList , (GFunc)g_free , NULL) ;
- g_list_free(prefsList) ;
- }
- channelStateMsg(thisConv) ; chatBufferDump(thisConv) ;
- }
- void helpResp(PurpleConversation* thisConv)
- {
- unsigned int i ; GList* helpIter ;
- for (i = 0 ; i < N_UNIQ_CMDS ; ++i)
- {
- helpIter = g_list_first(purple_cmd_help(NULL , Commands[i])) ;
- while (helpIter)
- {
- chatBufferPut(helpIter->data) ; chatBufferDump(thisConv) ;
- helpIter = g_list_next(helpIter) ;
- }
- }
- }
- void channelStateMsg(PurpleConversation* thisConv)
- {
- // NOTE: callers of channelStateMsg() should eventually call chatBufferDump()
- char thisBridgeName[SM_BUFFER_SIZE] ;
- chatBufferCatSS(THIS_CHANNEL_MSG , " ") ;
- getBridgeName(thisConv , thisBridgeName) ;
- if (isBlank(thisBridgeName)) chatBufferCat(UNBRIDGED_MSG) ;
- else chatBufferCatSSSS(THIS_BRIDGE_MSG , " '" , thisBridgeName , "'") ;
- }
- void bridgeStatsMsg(const char* bridgeName)
- {
- // NOTE: callers of bridgeStatsMsg() should eventually call chatBufferDump()
- unsigned int nChannels ;
- GList* channelsList ; GList* channelsIter ; char* aChannelUid ;
- GList* activeChannelsIter = NULL ; gboolean isActive = FALSE ;
- char* activeMsg ; char* protocol ; char* username ; const char* channelName ;
- char* network ; char nick[SM_BUFFER_SIZE] ;
- #if DEBUG_LOGIC
- DBGss("bridgeStatsMsg() bridgeName='" , bridgeName , "' " , ((doesBridgeExist(bridgeName))? "exists" : "not exists - bailing")) ;
- #endif
- // display non-existent bridge state
- if (!doesBridgeExist(bridgeName))
- {
- if (!getNBridges()) chatBufferCatSS(NO_BRIDGES_MSG , "") ;
- else chatBufferCatSSSS(NO_SUCH_BRIDGE_MSG , " '" , bridgeName , "'") ;
- return ;
- }
- else chatBufferCatSSSS(STATS_MSGc , " '" , bridgeName , "' - ") ;
- // display bridge state
- prepareBridgeKeys(bridgeName) ;
- nChannels = getNChannels(BridgeKeyBuffer) ;
- if (!nChannels) chatBufferCat(STATS_DELETED_MSG) ;
- else
- {
- if (isBridgeEnabled(bridgeName)) chatBufferCat(STATS_ENABLED_MSG) ;
- else chatBufferCat(STATS_DISABLED_MSG) ;
- channelUidBufferPutD("%d" , nChannels) ;
- chatBufferCatSSSS(" - " , ChannelUidBuffer , " " , STATS_MSGd) ;
- }
- // display channels
- channelsList = purple_prefs_get_string_list(BridgeKeyBuffer) ;
- channelsIter = g_list_first(channelsList) ;
- while (channelsIter)
- {
- #if DEBUG_LOGIC
- DBGss("bridgeStatsMsg() found stored channelUid='" , (char*)channelsIter->data , "'" , "") ;
- #endif
- aChannelUid = (char*)channelsIter->data ;
- // determine if bridged aChannel is opened or closed
- activeChannelsIter = g_list_first(purple_get_conversations()) ;
- while (activeChannelsIter)
- {
- #if DEBUG_VB
- if (channelsIter == g_list_first(channelsList))
- DBGss("bridgeStatsMsg() got active channelName='" , getChannelName((PurpleConversation*)activeChannelsIter->data) , "'" , "") ;
- #endif
- prepareChannelUid((PurpleConversation*)activeChannelsIter->data) ;
- isActive |= !strcmp(ChannelUidBuffer , aChannelUid) ;
- activeChannelsIter = g_list_next(activeChannelsIter) ;
- }
- activeMsg = (isActive)? CH_ACTIVE_MSG : CH_INACTIVE_MSG ;
- #if DEBUG_VB
- DBGss("bridgeStatsMsg() aChannel='" , aChannelUid , "' " , activeMsg) ;
- #endif
- // parse channel data from aChannelUid
- channelUidBufferPutS("%s" , aChannelUid) ;
- if (!(protocol = strtok(ChannelUidBuffer , UID_DELIMITER)) ||
- !(username = strtok(NULL , UID_DELIMITER)) ||
- !(channelName = strtok(NULL , UID_DELIMITER)))
- continue ;
- #if DEBUG_VB
- DBGsssss("bridgeStatsMsg() parsed channelUid " , activeMsg , " protocol='" , protocol , "' username='" , username , "' channelName='" , channelName , "'" , "") ;
- #endif
- // display channel data
- chatBufferCatSSSSSS("\n " , activeMsg , " '" , channelName , "' on '" , protocol) ;
- if (!strcmp(protocol , IRC_PROTOCOL) &&
- (network = strchr(username , '@')) &&
- (strncpy(nick , username , network - username)))
- {
- nick[network - username] = '\0' ;
- chatBufferCatSSSS(network , "' as '" , nick , "'") ;
- }
- else chatBufferCatSSS("' as '" , username , "'") ;
- channelsIter = g_list_next(channelsIter) ;
- }
- }
- void bridgeStatsMsgEach(const char* bridgePrefKey , void* unusedGListEachData)
- {
- char bridgeName[SM_BUFFER_SIZE] ; prefKey2Name(bridgePrefKey , bridgeName) ;
- if (isChannelsPref(bridgePrefKey)) bridgeStatsMsg(bridgeName) ; chatBufferCat("\n") ;
- }
- /* text buffer helpers */
- gboolean isBlank(const char* aCstring) { return (!aCstring || !*aCstring) ; }
- void channelUidBufferPutS(const char* fmt , const char* s1)
- { snprintf(ChannelUidBuffer , SM_BUFFER_SIZE , fmt , s1) ; }
- void channelUidBufferPutD(const char* fmt , int d1)
- { snprintf(ChannelUidBuffer , SM_BUFFER_SIZE , fmt , d1) ; }
- void chatBufferClear() { ChatBuffer[0] = '\0' ; }
- void chatBufferPut( const char* s)
- { snprintf(ChatBuffer , LG_BUFFER_SIZE , "%s" , s) ; }
- void chatBufferPutSS( const char* fmt , const char* s1 , const char* s2)
- { snprintf(ChatBuffer , LG_BUFFER_SIZE , fmt , s1 , s2) ; }
- void chatBufferPutSSS( const char* fmt , const char* s1 , const char* s2 , const char* s3)
- { snprintf(ChatBuffer , LG_BUFFER_SIZE , fmt , s1 , s2 , s3) ; }
- void chatBufferPutSDS( const char* fmt , const char* s1 , int d1 , const char* s2)
- { snprintf(ChatBuffer , LG_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 , LG_BUFFER_SIZE , fmt , s1 , s2 , s3 , s4) ; }
- void chatBufferCat( const char* s)
- { strncat(ChatBuffer , s , LG_BUFFER_SIZE - strlen(ChatBuffer) - 1) ; }
- void chatBufferCatSS( const char* s1 , const char* s2)
- { chatBufferCat(s1) ; chatBufferCat(s2) ; }
- void chatBufferCatSSS( const char* s1 , const char* s2 , const char* s3)
- { chatBufferCat(s1) ; chatBufferCat(s2) ; chatBufferCat(s3) ; }
- void chatBufferCatSSSS( const char* s1 , const char* s2 , const char* s3 ,
- const char* s4)
- { chatBufferCat(s1) ; chatBufferCat(s2) ; chatBufferCat(s3) ; chatBufferCat(s4) ; }
- void chatBufferCatSSSSS( const char* s1 , const char* s2 , const char* s3 ,
- const char* s4 , const char* s5)
- { chatBufferCat(s1) ; chatBufferCat(s2) ; chatBufferCat(s3) ; chatBufferCat(s4) ;
- chatBufferCat(s5) ; }
- void chatBufferCatSSSSSS(const char* s1 , const char* s2 , const char* s3 ,
- const char* s4 , const char* s5 , const char* s6)
- { chatBufferCat(s1) ; chatBufferCat(s2) ; chatBufferCat(s3) ; chatBufferCat(s4) ;
- chatBufferCat(s5) ; chatBufferCat(s6) ; }
- void prepareRelayChat(char* prefix , const char* sender , char* msg)
- { chatBufferPutSSSS(CHAT_OUT_FMT , prefix , sender , NICK_POSTFIX , msg) ; }
- void chatBufferDump(PurpleConversation* thisConv)
- {
- #if DEBUG_CHAT
- DBGs("chatBufferDump() ChatBuffer=\n" , ChatBuffer) ;
- #endif
- purple_conversation_write(thisConv , BRIDGIN_NICK , ChatBuffer ,
- PURPLE_MESSAGE_SYSTEM , time(0)) ;
- chatBufferClear() ;
- }
- void relayMessage(char* thisBridgeName , PurpleConversation* thisConv)
- {
- // NOTE: thisConv will be excluded from the relay - pass in NULL to include it
- GList* activeChannelsIter = NULL ; PurpleConversation* aConv ;
- char aBridgeName[SM_BUFFER_SIZE] ; unsigned int convType ;
- activeChannelsIter = g_list_first(purple_get_conversations()) ;
- while (activeChannelsIter)
- {
- aConv = (PurpleConversation*)activeChannelsIter->data ;
- getBridgeName(aConv , aBridgeName) ;
- #if DEBUG_VB
- DBGss("relayMessage() got active channelName='" , getChannelName(aConv) ,
- ((aConv == thisConv)? " isThisChannel - skipping" :
- ((!strcmp(aBridgeName , thisBridgeName))? "' isThisBridge - relaying" : "' notThisBridge - skipping" )) , "") ;
- #endif
- if (aConv != thisConv && !strcmp(aBridgeName , thisBridgeName))
- {
- 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) ;
- }
- }
- void relayMessageEach(const char* bridgePrefKey , PurpleConversation* thisConv)
- {
- char bridgeName[SM_BUFFER_SIZE] ; prefKey2Name(bridgePrefKey , bridgeName) ;
- if (isChannelsPref(bridgePrefKey)) relayMessage(bridgeName , thisConv) ;
- }
- void alert(char* msg)
- {
- purple_notify_message(ThisPlugin , PURPLE_NOTIFY_MSG_INFO , msg ,
- PLUGIN_VERSION , NULL , NULL , NULL) ;
- }
- /* main */
- PURPLE_INIT_PLUGIN(PLUGIN_NAME , handlePluginInit , PluginInfo)
|