]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
Merge remote branch 'origin/master' into akari/irc akari/irc
authorSamual <samual@xonotic.org>
Sat, 20 Aug 2011 10:20:39 +0000 (06:20 -0400)
committerSamual <samual@xonotic.org>
Sat, 20 Aug 2011 10:20:39 +0000 (06:20 -0400)
Conflicts:
makefile.inc

cl_main.c
cl_video.c
console.c
irc.c [new file with mode: 0755]
irc.h [new file with mode: 0755]
keys.c
makefile.inc

index 420203b4f4e0c641d2fe54887432550e4c1a46d1..f9226401d9ff5fd5dda505e3c38fd73520141360 100644 (file)
--- a/cl_main.c
+++ b/cl_main.c
@@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "r_shadow.h"
 #include "libcurl.h"
 #include "snd_main.h"
+#include "irc.h"
 
 // we need to declare some mouse variables here, because the menu system
 // references them even when on a unix system.
@@ -2502,6 +2503,7 @@ void CL_Init (void)
 
        CL_Video_Init();
        CL_Gecko_Init();
+       CL_Irc_Init();
 }
 
 
index 7c4b2a5ebda32f919e79f0174902a421445c7a85..095db75e32df2e3f236fedad451003ed10322c74 100644 (file)
@@ -704,4 +704,4 @@ void CL_Video_Init( void )
        Cvar_RegisterVariable(&cl_video_fadeout);
 
        R_RegisterModule( "CL_Video", cl_video_start, cl_video_shutdown, cl_video_newmap, NULL, NULL );
-}
\ No newline at end of file
+}
index 48dcac3ddf6405878af9dda911f8b66e08c06cfb..e89ad5314346361e2eaa7e17db503b3d30167df3 100644 (file)
--- a/console.c
+++ b/console.c
@@ -29,6 +29,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // for u8_encodech
 #include "ft2.h"
 
+#include <pthread.h>
+
 float con_cursorspeed = 4;
 
 // lines up from bottom to display
@@ -1047,12 +1049,19 @@ Con_MaskPrint
 extern cvar_t timestamps;
 extern cvar_t timeformat;
 extern qboolean sys_nostdout;
+
+// -- Akari: attempted to make this somewhat thread safe.... works.... sometimes
+
+pthread_mutex_t con_print_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 void Con_MaskPrint(int additionalmask, const char *msg)
 {
        static int mask = 0;
        static int index = 0;
        static char line[MAX_INPUTLINE];
 
+       pthread_mutex_lock(&con_print_mutex);
+
        for (;*msg;msg++)
        {
                Con_Rcon_AddChar(*msg);
@@ -1319,6 +1328,8 @@ void Con_MaskPrint(int additionalmask, const char *msg)
                        mask = 0;
                }
        }
+       
+       pthread_mutex_unlock(&con_print_mutex);
 }
 
 /*
@@ -1742,11 +1753,20 @@ void Con_DrawNotify (void)
 
                // LordHavoc: speedup, and other improvements
                if (chat_mode < 0)
-                       dpsnprintf(temptext, sizeof(temptext), "]%s%s", chat_buffer, cursor);
+                       dpsnprintf(temptext, sizeof(temptext), "]%s%c", chat_buffer, cursor);
+               else if(chat_mode == 2)
+               {
+                       if(chat_buffer[0] == '#' || chat_buffer[0] == '&') //Channels are yellow, nicks are green
+                               dpsnprintf(temptext, sizeof(temptext), "(IRC)target:^3%s^7%c", chat_buffer, cursor);
+                       else
+                               dpsnprintf(temptext, sizeof(temptext), "(IRC)target:^2%s^7%c", chat_buffer, cursor);
+               }
+               else if(chat_mode == 3)
+                       dpsnprintf(temptext, sizeof(temptext), "(IRC)message:%s%c", chat_buffer, cursor);
                else if(chat_mode)
-                       dpsnprintf(temptext, sizeof(temptext), "say_team:%s%s", chat_buffer, cursor);
+                       dpsnprintf(temptext, sizeof(temptext), "say_team:%s%c", chat_buffer, cursor);
                else
-                       dpsnprintf(temptext, sizeof(temptext), "say:%s%s", chat_buffer, cursor);
+                       dpsnprintf(temptext, sizeof(temptext), "say:%s%c", chat_buffer, cursor);
 
                // FIXME word wrap
                inputsize = (numChatlines ? con_chatsize : con_notifysize).value;
diff --git a/irc.c b/irc.c
new file mode 100755 (executable)
index 0000000..cd06928
--- /dev/null
+++ b/irc.c
@@ -0,0 +1,825 @@
+//      irc.c
+//      
+//      Copyright 2011 Akari <Akari` @ irc.quakenet.org>
+//      
+//      This program is free software; you can redistribute it and/or modify
+//      it under the terms of the GNU General Public License as published by
+//      the Free Software Foundation; either version 2 of the License, or
+//      (at your option) any later version.
+//      
+//      This program 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 General Public License for more details.
+
+#include <pthread.h>
+#include <string.h>
+
+#include "quakedef.h"
+#include "irc.h"
+#include "cvar.h"
+
+cvar_t irc_server = {CVAR_SAVE, "irc_server", "", "IRC server to connect to"};
+cvar_t irc_port = {CVAR_SAVE, "irc_port", "6667", "Port of the IRC server"};
+cvar_t irc_password = {CVAR_SAVE, "irc_password", "", "IRC server password"};
+cvar_t irc_nick = {CVAR_SAVE, "irc_nick", "", "Your nickname to use on IRC. Note: this cvar only defines your prefered nick, do NOT use this to change your nickname while connected, use irc_chnick instead"};
+cvar_t irc_connected = {CVAR_READONLY, "irc_connected", "0", "IRC connection state (0 = not connected, 1 = connecting, 2 = connected, 3 = disconnecting)"};
+cvar_t irc_msgprefix = {CVAR_SAVE, "irc_msgprefix", "^5IRC^0|^7", "What all IRC events will be prefixed with when printed to the console"};
+cvar_t irc_chatwindow = {CVAR_SAVE, "irc_chatwindow", "2", "0 = IRC messages will be printed in the console only, 1 = IRC messages will go to the chat window, 2 = Only hilights and private messages will appear in the chat window"};
+cvar_t irc_numeric_errorsonly = {CVAR_SAVE, "irc_numeric_errorsonly", "0", "If 1, any numeric event below 400 won't be printed'"};
+cvar_t irc_save_target = {CVAR_SAVE, "irc_save_target", "1", "Whether to save target for irc_messagemode or not"};
+cvar_t irc_current_nick = {CVAR_READONLY, "irc_current_nick", "", "Holds your current IRC nick"};
+cvar_t irc_hilights = {CVAR_SAVE, "irc_hilights", "", "Space separated list of words to hilight"};
+cvar_t irc_autochangetarget = {CVAR_SAVE, "irc_autochangetarget", "0", "if 1, will automatically change target for irc_messagemode when a hilight or a private message is recieved, so you can reply instantly. Requires irc_save_target"};
+cvar_t irc_watched_channels = {CVAR_SAVE, "irc_watched_channels", "", "Space separated list of watched channels. PRIVMSGs from those channels will be always printed to the chat area, regardless of irc_chatwindow setting"};
+
+irc_session_t *irc_session_global = NULL;
+int irc_msgmode;
+char last_channel[MAX_INPUTLINE];
+
+//
+//  Initialization
+//
+
+void CL_Irc_Init(void)
+{
+    Cvar_RegisterVariable(&irc_server);
+    Cvar_RegisterVariable(&irc_port);
+    Cvar_RegisterVariable(&irc_password);
+    Cvar_RegisterVariable(&irc_nick);
+    Cvar_RegisterVariable(&irc_connected);
+    Cvar_RegisterVariable(&irc_msgprefix);
+    Cvar_RegisterVariable(&irc_chatwindow);
+    Cvar_RegisterVariable(&irc_numeric_errorsonly);
+    Cvar_RegisterVariable(&irc_save_target);
+    Cvar_RegisterVariable(&irc_current_nick);
+    Cvar_RegisterVariable(&irc_hilights);
+    Cvar_RegisterVariable(&irc_autochangetarget);
+    Cvar_RegisterVariable(&irc_watched_channels);
+    
+    Cmd_AddCommand ("irc_connect", CL_Irc_Connect_f, "Connects you to the IRC server");
+    Cmd_AddCommand ("irc_disconnect", CL_Irc_Disconnect_f, "Disconnects you from the IRC server");
+    Cmd_AddCommand ("irc_say", CL_Irc_Say_f, "Sends a privmsg to a channel or nick");
+    Cmd_AddCommand ("irc_notice", CL_Irc_Notice_f, "Sends a notice to a channel or nick");
+    Cmd_AddCommand ("irc_me", CL_Irc_Me_f, "Sends a CTCP ACTION (/me) to a channel or nick");
+    Cmd_AddCommand ("irc_join", CL_Irc_Join_f, "Joins an IRC channel");
+    Cmd_AddCommand ("irc_part", CL_Irc_Part_f, "Parts an IRC channel");
+    Cmd_AddCommand ("irc_names", CL_Irc_Names_f, "Lists users of an IRC channel");
+    Cmd_AddCommand ("irc_messagemode", CL_Irc_MessageMode_f, "Interactive prompt for sending IRC messages. Meant to be bound to a key");
+    Cmd_AddCommand ("irc_chnick", CL_Irc_ChNick_f, "Changes your nick");
+    Cmd_AddCommand ("irc_raw", CL_Irc_Raw_f, "Sends a raw string to the IRC server");
+}
+
+//
+//  Function that starts IRC main loop in a thread
+//
+
+static void IRC_Thread(void *p)
+{
+    if(irc_run(irc_session_global))
+    {
+        if(irc_connected.integer == 3) //irc_disconnect
+        {
+            Cvar_SetQuick(&irc_connected, "0");
+            return;
+        }
+        
+        Con_Printf("%s^1Error: ^7%s\n",
+            irc_msgprefix.string,
+            irc_strerror(irc_errno(irc_session_global))
+        );
+        
+        CL_Irc_Disconnect_f();
+        return;
+    }
+}
+
+//
+//  irc_ console commands callbacks
+//
+
+static void CL_Irc_Connect_f(void)
+{
+    irc_callbacks_t cb;
+    pthread_t irc_thread;
+    
+    switch(irc_connected.integer)
+    {
+        case 1:
+            Con_Printf("%sAlready connecting to %s:%i\n",
+                irc_msgprefix.string, 
+                irc_server.string,
+                irc_port.integer
+            );
+            return;
+        
+        case 2:
+            Con_Printf("%sAlready connected to %s:%i.\n",
+                irc_msgprefix.string,
+                irc_server.string,
+                irc_port.integer
+            );
+            return;
+    }
+    
+    if(NOTSET(irc_server))
+    {
+        Con_Printf("Please set the irc_server variable\n");
+        return;
+    }
+    
+    if(NOTSET(irc_nick))
+    {
+        Con_Printf("Please set the irc_nick variable\n");
+        return;
+    }
+    
+    if(NOTSET(irc_port))
+    {
+        Con_Printf("Please set the irc_port variable\n");
+        return;
+    }
+    
+    Cvar_SetQuick(&irc_connected, "1");
+    
+    memset(&cb, 0, sizeof(cb));
+    cb.event_connect = event_connect;
+    cb.event_numeric = event_numeric;
+    cb.event_privmsg = event_privmsg;
+    cb.event_channel = event_channel;
+    cb.event_nick    = event_nick;
+    cb.event_quit    = event_quit;
+    cb.event_join    = event_join;
+    cb.event_part    = event_part;
+    cb.event_mode    = event_mode;
+    cb.event_umode   = event_umode;
+    cb.event_topic   = event_topic;
+    cb.event_kick    = event_kick;
+    cb.event_notice  = event_notice;
+    cb.event_invite  = event_invite;
+    cb.event_ctcp_action = event_ctcp_action;
+
+    Cvar_SetQuick(&irc_current_nick, irc_nick.string);
+
+    irc_session_global = irc_create_session(&cb);
+    irc_option_set(irc_session_global, LIBIRC_OPTION_STRIPNICKS);
+    if(irc_connect(
+        irc_session_global,
+        irc_server.string,
+        irc_port.integer,
+        NOTSET(irc_password)? NULL : irc_password.string,
+        irc_nick.string,
+        "dpirc", "DPIRC user"
+    ))
+    {   //Connection failed
+        Con_Printf("%s^1Connection failed: ^7%s\n",
+            irc_msgprefix.string,
+            irc_strerror(irc_errno(irc_session_global))
+        );
+        
+        CL_Irc_Disconnect_f();
+        return;
+    }
+    
+    pthread_create (&irc_thread, NULL, (void *) &IRC_Thread, NULL);
+}
+
+static void CL_Irc_Disconnect_f(void)
+{
+    if(!irc_connected.integer)
+    {
+        Con_Printf("%sNot connected\n",
+            irc_msgprefix.string
+        );
+        
+        return;
+    }
+    
+    Con_Printf("^1Disconnected from the IRC server\n");
+    Cvar_SetQuick(&irc_connected, "3");
+    irc_cmd_quit(irc_session_global, "Disconnected");
+    irc_destroy_session(irc_session_global);
+}
+
+static void CL_Irc_Say_Universal_f(void)
+{
+    int cmdlen, i, j, space;
+    const char *cmd, *dest;
+    char message[MAX_INPUTLINE];
+    qboolean watched;
+
+    if(Cmd_Argc() < 3) switch(irc_msgmode)
+    {
+        case MSGMODE_PRIVMSG:
+            Con_Printf("Usage: irc_say channel_or_nick message\n");
+            return;
+        case MSGMODE_NOTICE:
+            Con_Printf("Usage: irc_notice channel_or_nick message\n");
+            return;
+        case MSGMODE_ACTION:
+            Con_Printf("Usage: irc_me channel_or_nick message\n");
+            return;
+    }
+    
+    cmd = Cmd_Args();
+    cmdlen = strlen(cmd);
+    
+    space = 0;
+    for(i = 0, j = 0; i < cmdlen; ++i)
+    {
+        if(space)
+        {
+            message[j++] = cmd[i];
+        }
+        else if(cmd[i] == ' ') ++space;
+    }
+    
+    message[j] = '\0';
+    
+    dest = Cmd_Argv(1);
+    
+    switch(irc_msgmode)
+    {
+        case MSGMODE_PRIVMSG:
+            irc_cmd_msg(irc_session_global, dest, message);
+            watched = Irc_IsWatchedChannel(dest);
+            
+            if(ISCHANNEL(dest)) Con_Printf("%s%s^3%s^0|^7<^2%s^7> %s\n",
+                watched? "\001" : CHATWINDOW,
+                irc_msgprefix.string,
+                dest,
+                irc_current_nick.string,
+                message
+            ); else Con_Printf("%s%s^1Privmsg to ^2%s^7: ^3%s\n",
+                CHATWINDOW_URGENT,
+                irc_msgprefix.string,
+                dest,
+                message
+            );
+            
+            break;
+        
+        case MSGMODE_NOTICE:
+            irc_cmd_notice(irc_session_global, dest, message);
+            
+            if(!ISCHANNEL(dest)) Con_Printf("%s%sNotice to ^2%s^7: ^9%s\n",
+                CHATWINDOW,
+                irc_msgprefix.string,
+                dest,
+                message
+            ); else Con_Printf("%s%s^3%s^0|^9-^2%s^9- %s\n",
+                CHATWINDOW,
+                irc_msgprefix.string,
+                dest,
+                irc_current_nick.string,
+                message
+            );
+            
+            break;
+        
+        case MSGMODE_ACTION:
+            irc_cmd_me(irc_session_global, dest, message);
+            
+            if(ISCHANNEL(dest)) Con_Printf("%s%s^3%s^0| ^2* %s ^7%s\n",
+                watched? "\001" : CHATWINDOW,
+                irc_msgprefix.string,
+                dest,
+                irc_current_nick.string,
+                message
+            ); else Con_Printf("%s%s^1Privmsg to ^2%s^7: ^2* %s ^3%s\n",
+                CHATWINDOW_URGENT,
+                irc_msgprefix.string,
+                dest,
+                irc_current_nick.string,
+                message
+            );
+            break;
+    }
+}
+
+static void CL_Irc_Raw_f(void)
+{
+    if(Cmd_Argc() < 2)
+    {
+        Con_Printf("Usage: irc_raw command\n");
+        return;
+    }
+    
+    irc_send_raw(irc_session_global, "%s", Cmd_Args());
+}
+
+static void CL_Irc_Say_f(void)
+{
+    MUSTCONNECT
+    irc_msgmode = MSGMODE_PRIVMSG;
+    CL_Irc_Say_Universal_f();
+}
+
+static void CL_Irc_Notice_f(void)
+{
+    MUSTCONNECT
+    irc_msgmode = MSGMODE_NOTICE;
+    CL_Irc_Say_Universal_f();
+}
+
+static void CL_Irc_Me_f(void)
+{
+    MUSTCONNECT
+    irc_msgmode = MSGMODE_ACTION;
+    CL_Irc_Say_Universal_f();
+}
+
+static void CL_Irc_Join_f(void)
+{
+    int argc = Cmd_Argc();
+    const char *channel;
+    
+    MUSTCONNECT
+    
+    if(argc < 2)
+    {
+        Con_Printf("Usage: irc_join channel [key]\n");
+        return;
+    }
+    
+    channel = Cmd_Argv(1);
+    
+    if(argc > 2)
+        irc_cmd_join(irc_session_global, channel, Cmd_Argv(2));
+    else
+        irc_cmd_join(irc_session_global, channel, NULL);
+}
+
+static void CL_Irc_Part_f(void)
+{
+    MUSTCONNECT
+    
+    if(Cmd_Argc() < 2)
+    {
+        Con_Printf("Usage: irc_part channel\n");
+        return;
+    }
+    
+    irc_cmd_part(irc_session_global, Cmd_Argv(1));
+}
+
+static void CL_Irc_Names_f(void)
+{
+    MUSTCONNECT
+    
+    if(Cmd_Argc() < 2)
+    {
+        Con_Printf("Usage: irc_names channel\n");
+        return;
+    }
+    
+    irc_cmd_names(irc_session_global, Cmd_Argv(1));
+}
+
+void CL_Irc_MessageMode_f(void)
+{
+    const char *tmp;
+    
+    key_dest = key_message;
+    chat_mode = 2;
+    chat_bufferlen = 0;
+    chat_buffer[0] = 0;
+    
+    if(irc_save_target.integer)
+    {
+        tmp = Irc_GetLastChannel();
+        strlcpy(chat_buffer, tmp, sizeof(chat_buffer));
+        chat_bufferlen = strlen(chat_buffer);
+    }
+}
+
+void CL_Irc_ChNick_f(void)
+{
+    MUSTCONNECT
+    
+    if(Cmd_Argc() < 2)
+    {
+        Con_Printf("Usage: irc_chnick nick\n");
+        return;
+    }
+    
+    irc_cmd_nick(irc_session_global, Cmd_Argv(1));
+}
+
+
+void Irc_SetLastChannel(const char *value)
+{
+    strlcpy(last_channel, value, sizeof(last_channel));
+}
+
+const char* Irc_GetLastChannel(void)
+{
+    return last_channel;
+}
+
+
+void Irc_SendMessage(const char *message)
+{
+    const char* dest = Irc_GetLastChannel();
+    qboolean watched = Irc_IsWatchedChannel(dest);
+    
+    MUSTCONNECT
+    
+    irc_cmd_msg(irc_session_global, dest, message);
+            
+    if(ISCHANNEL(dest)) Con_Printf("%s%s^3%s^0|^7<^2%s^7> %s\n",
+        watched? "\001" : CHATWINDOW,
+        irc_msgprefix.string,
+        dest,
+        irc_current_nick.string,
+        message
+    ); else Con_Printf("%s%s^1Privmsg to ^2%s^7: ^3%s\n",
+        CHATWINDOW_URGENT,
+        irc_msgprefix.string,
+        dest,
+        message
+    );
+}
+
+//
+//  IRC events
+//
+
+IRCEVENT(event_connect)
+{
+    Cvar_SetQuick(&irc_connected, "2");
+    Con_Printf("%sConnected to %s:%i\n",
+        irc_msgprefix.string, 
+        irc_server.string,
+        irc_port.integer
+    );
+}
+
+IRCNUMEVENT(event_numeric)
+{
+    //Get our initial nick from the welcome message
+    if(event == 001)
+        Cvar_SetQuick(&irc_current_nick, params[0]);
+    
+    if (!irc_numeric_errorsonly.integer || event > 400)
+    {
+        Con_Printf("%s^3%d ^2%s ^1%s^7 %s %s %s\n",
+            irc_msgprefix.string,
+            event,
+            origin ? origin : "^8(unknown)",
+            params[0],
+            count > 1 ? params[1] : "",
+            count > 2 ? params[2] : "",
+            count > 3 ? params[3] : ""
+        );
+    }
+}
+
+IRCEVENT(event_privmsg)
+{
+    char* msgstr = "";
+    
+    if(count > 1)
+        msgstr = irc_color_strip_from_mirc(params[1]);
+    
+    UPDATETARGET(origin)
+    
+    Con_Printf("%s%s^1Privmsg from ^2%s^7: ^3%s\n",
+        CHATWINDOW_URGENT,
+        irc_msgprefix.string,
+        origin,
+        msgstr
+    );
+    
+    if(count > 1) free(msgstr);
+}
+
+
+IRCEVENT(event_channel)
+{
+    char* msgstr = "";
+    qboolean watched;
+    
+    //weird shit
+    if(!ISCHANNEL(params[0]))
+        return event_privmsg(session, event, origin, params, count);
+    
+    if(count > 1)
+        msgstr = irc_color_strip_from_mirc(params[1]);
+    
+    watched = Irc_IsWatchedChannel(params[0]);
+    
+    if(Irc_CheckHilight(msgstr))
+    {   
+        UPDATETARGET(params[0])
+        
+        Con_Printf("%s%s^3%s^0|^7<^2%s^7> ^1%s\n",
+            watched? "\001" : CHATWINDOW_URGENT,
+            irc_msgprefix.string,
+            params[0],
+            origin,
+            msgstr
+        );
+    }
+    else Con_Printf("%s%s^3%s^0|^7<^2%s^7> %s\n",
+        watched? "\001" : CHATWINDOW,
+        irc_msgprefix.string,
+        params[0],
+        origin,
+        msgstr
+    );
+    
+    if(count > 1) free(msgstr);
+}
+
+IRCEVENT(event_nick)
+{
+    //printf("%sorigin -> %s (%s, %s)\n", origin, params[0], irc_current_nick.string, irc_nick.string);
+    //crash!
+    //cvar_t dumb;
+    //Cvar_SetQuick(&dumb, NULL);
+    
+    if(!strncmp(origin, irc_current_nick.string, 512)) //Our nick is changed
+    {
+        Cvar_SetQuick(&irc_current_nick, params[0]);
+        
+        Con_Printf("%s%s^7Your nick is now ^2%s\n",
+            CHATWINDOW,
+            irc_msgprefix.string,
+            params[0]
+        );
+        
+        return;
+    }
+    
+    Con_Printf("%s%s^2%s^7 is now known as ^2%s\n",
+        CHATWINDOW,
+        irc_msgprefix.string,
+        origin,
+        params[0]
+    );
+}
+
+IRCEVENT(event_quit)
+{
+    Con_Printf("%s%s^2%s^7 has quit IRC: ^2%s\n",
+        CHATWINDOW,
+        irc_msgprefix.string,
+        origin,
+        count? params[0] : "^8(quit message missing)"
+    );
+}
+
+IRCEVENT(event_join)
+{
+    Con_Printf("%s%s^2%s^7 has joined ^3%s\n",
+        CHATWINDOW,
+        irc_msgprefix.string,
+        origin,
+        params[0]
+    );
+}
+
+IRCEVENT(event_part)
+{
+    Con_Printf("%s%s^2%s^7 has left ^3%s^7: %s\n",
+        CHATWINDOW,
+        irc_msgprefix.string,
+        origin,
+        params[0],
+        count > 1? params[1] : "^8(part message missing)"
+    );
+}
+
+IRCEVENT(event_mode)
+{
+    char paramstring[MAX_INPUTLINE] = "";
+    unsigned int i;
+    
+    for(i = 2; i < count; i++)
+    {
+        strlcat(paramstring, params[i], sizeof(paramstring));
+        strlcat(paramstring, " ", sizeof(paramstring));
+    }
+    
+    Con_Printf("%s%s^2%s^7 set mode on ^3%s^7: %s %s\n",
+        CHATWINDOW,
+        irc_msgprefix.string,
+        origin,
+        params[0],
+        params[1],
+        paramstring
+    );
+}
+
+IRCEVENT(event_umode)
+{
+    Con_Printf("%sUsermode changed for ^2%s^7: %s\n",
+        irc_msgprefix.string,
+        origin,
+        params[0]
+    );
+}
+
+IRCEVENT(event_topic)
+{
+    if(count > 1) Con_Printf("%s%s^2%s^7 changed the topic of ^3%s^7: %s\n",
+        CHATWINDOW,
+        irc_msgprefix.string,
+        origin,
+        params[0],
+        params[1]
+    );
+}
+
+IRCEVENT(event_kick)
+{
+    Con_Printf("%s%s^2%s^7 has kicked ^2%s^7 out of ^3%s^7: %s\n",
+        CHATWINDOW,
+        irc_msgprefix.string,
+        origin,
+        count > 1? params[1] : "^8(nick missing)", //libircclient documentation says params[1] is optinal.
+        params[0],
+        count > 2? params[2] : "^8(random kick victim! yay!)"
+    );
+}
+
+IRCEVENT(event_notice)
+{
+    char* msgstr = "";
+    
+    if(count > 1)
+        msgstr = irc_color_strip_from_mirc(params[1]);
+    
+    if(!ISCHANNEL(params[0])) Con_Printf("%s%sNotice from ^2%s^7: ^9%s\n",
+        CHATWINDOW,
+        irc_msgprefix.string,
+        origin,
+        msgstr
+    ); else Con_Printf("%s%s^3%s^0|^9-^2%s^9- %s\n",
+        CHATWINDOW,
+        irc_msgprefix.string,
+        params[0],
+        origin,
+        msgstr
+    );
+    
+    if(count > 1) free(msgstr);
+}
+
+IRCEVENT(event_invite)
+{
+    Con_Printf("%s%s^2%s^7 invites you to ^3%s\n",
+        CHATWINDOW,
+        irc_msgprefix.string,
+        origin,
+        params[1]
+    );
+}
+
+IRCEVENT(event_ctcp_action)
+{
+    char* msgstr = "";
+    qboolean watched;
+    
+    if(!ISCHANNEL(params[0]))
+    {
+        event_ctcp_action_priv(session, event, origin, params, count);
+        return;
+    }
+    
+    if(count > 1)
+        msgstr = irc_color_strip_from_mirc(params[1]);
+    
+    watched = Irc_IsWatchedChannel(params[0]);
+    
+    if(Irc_CheckHilight(msgstr))
+    {   
+        UPDATETARGET(params[0])
+        
+        Con_Printf("%s%s^3%s^0| ^1* %s ^7%s\n",
+            watched? "\001" : CHATWINDOW_URGENT,
+            irc_msgprefix.string,
+            params[0],
+            origin,
+            msgstr
+        );
+    }
+    else Con_Printf("%s%s^3%s^0| ^2* %s ^7%s\n",
+        watched? "\001" : CHATWINDOW,
+        irc_msgprefix.string,
+        params[0],
+        origin,
+        msgstr
+    );
+    
+    if(count > 1) free(msgstr);
+}
+
+//called by event_ctcp_action
+IRCEVENT(event_ctcp_action_priv)
+{
+    char* msgstr = "";
+    
+    if(count > 1)
+        msgstr = irc_color_strip_from_mirc(params[1]);
+    
+    UPDATETARGET(origin)
+    
+    Con_Printf("%s%s^1Privmsg^7: ^2* %s ^3%s\n",
+        CHATWINDOW_URGENT,
+        irc_msgprefix.string,
+        origin,
+        msgstr
+    );
+    
+    if(count > 1) free(msgstr);
+}
+
+//
+//  Function that checks if a message contains hilights
+//
+
+qboolean Irc_CheckHilight(const char *msg)
+{
+    int start, idx, len;
+    char buffer[512];
+    
+    if(strcasestr(msg, irc_current_nick.string))
+        return TRUE; //Contains our nick
+    
+    if(NOTSET(irc_hilights))
+        return FALSE;
+    
+    len = strlen(irc_hilights.string);
+    start = 0;
+    
+    for(idx = 0; idx < len; ++idx)
+    {
+        if(irc_hilights.string[idx] == ' ')
+        {
+            strlcpy(buffer, irc_hilights.string+start, idx+1);
+            if(strcasestr(msg, buffer))
+                return TRUE; //Contains a word from hilight list
+                
+            start = idx+1;
+        }
+    }
+    
+    //Catch the final word
+    strlcpy(buffer, irc_hilights.string+start, idx+1);
+    if(strcasestr(msg, buffer))
+        return TRUE; //Contains a word from hilight list
+    
+    return FALSE;
+}
+
+//
+//  Checks if channel is watched
+//
+
+qboolean Irc_IsWatchedChannel(const char* chan)
+{
+    int start, idx, len;
+    char buffer[512];
+    
+    if(NOTSET(irc_watched_channels))
+        return FALSE;
+    
+    len = strlen(irc_watched_channels.string);
+    start = 0;
+    
+    for(idx = 0; idx < len; ++idx)
+    {
+        if(irc_watched_channels.string[idx] == ' ')
+        {
+            strlcpy(buffer, irc_watched_channels.string+start, idx+1);
+            if(strcasestr(chan, buffer))
+                return TRUE;
+                
+            start = idx+1;
+        }
+    }
+    
+    //Catch the final channel
+    strlcpy(buffer, irc_watched_channels.string+start, idx+1);
+    if(strcasestr(chan, buffer))
+        return TRUE;
+    
+    return FALSE;
+}
+
+//
+//  Functions that should have been in libircclient
+//
+
+int irc_cmd_nick(irc_session_t * session, const char *nick)
+{
+    if(!nick)
+    {
+        //session->lasterror = LIBIRC_ERR_STATE; Won't compile
+        return 1;
+    }
+
+    return irc_send_raw(session, "NICK %s", nick);
+}
diff --git a/irc.h b/irc.h
new file mode 100755 (executable)
index 0000000..9444fb8
--- /dev/null
+++ b/irc.h
@@ -0,0 +1,73 @@
+//      irc.h
+//      
+//      Copyright 2011 Akari <Akari` @ irc.quakenet.org>
+//      
+//      This program is free software; you can redistribute it and/or modify
+//      it under the terms of the GNU General Public License as published by
+//      the Free Software Foundation; either version 2 of the License, or
+//      (at your option) any later version.
+//      
+//      This program 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 General Public License for more details.
+
+#include <libircclient/libircclient.h>
+
+#ifndef IRCINCLUDED
+#define IRCINCLUDED
+
+static void CL_Irc_Connect_f(void);
+static void CL_Irc_Disconnect_f(void);
+static void CL_Irc_Say_Universal_f(void);
+static void CL_Irc_Notice_f(void);
+static void CL_Irc_Me_f(void);
+static void CL_Irc_Say_f(void);
+static void CL_Irc_Join_f(void);
+static void CL_Irc_Part_f(void);
+static void CL_Irc_Names_f(void);
+static void CL_Irc_MessageMode_f(void);
+static void CL_Irc_ChNick_f(void);
+static void CL_Irc_Raw_f(void);
+void CL_Irc_Init (void);
+static void IRC_Thread(void *p);
+void Irc_SetLastChannel(const char *value);
+const char* Irc_GetLastChannel(void);
+void Irc_SendMessage(const char *msg);
+int irc_cmd_nick(irc_session_t * session, const char *nick);
+qboolean Irc_CheckHilight(const char* msg);
+qboolean Irc_IsWatchedChannel(const char* chan);
+
+#define IRCEVENT(funcname) void funcname(irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count)
+#define IRCNUMEVENT(funcname) void funcname (irc_session_t *session, unsigned int event, const char *origin, const char **params, unsigned int count)
+IRCEVENT(event_connect);
+IRCNUMEVENT(event_numeric);
+IRCEVENT(event_privmsg);
+IRCEVENT(event_channel);
+IRCEVENT(event_nick);
+IRCEVENT(event_quit);
+IRCEVENT(event_join);
+IRCEVENT(event_part);
+IRCEVENT(event_mode);
+IRCEVENT(event_umode);
+IRCEVENT(event_topic);
+IRCEVENT(event_kick);
+IRCEVENT(event_notice);
+IRCEVENT(event_invite);
+IRCEVENT(event_ctcp_action);
+IRCEVENT(event_ctcp_action_priv);
+
+#define MSGMODE_PRIVMSG 0
+#define MSGMODE_NOTICE  1
+#define MSGMODE_ACTION  2
+
+#define ISCHANNEL(c) (c[0] == '#' || c[0] == '&')
+#define CHATWINDOW (irc_chatwindow.integer == 1? "\001" : "")
+#define CHATWINDOW_URGENT (irc_chatwindow.integer? "\001" : "")
+#define MUSTCONNECT if(irc_connected.integer != 2) { Con_Printf("Not connected to an IRC server\n"); return; }
+#define UPDATETARGET(c) if(irc_autochangetarget.integer) Irc_SetLastChannel(c);
+#define NOTSET(cvar) (!strlen((cvar).string))
+
+extern char *strcasestr (__const char*, __const char*);
+
+#endif
diff --git a/keys.c b/keys.c
index aa84c237cb6ef7c0474e65b7d5d5731035dbc899..d16d44286b23ab43799ce77356e6a08f198d9d70 100644 (file)
--- a/keys.c
+++ b/keys.c
@@ -1194,6 +1194,10 @@ unsigned int     chat_bufferlen = 0;
 
 extern int Nicks_CompleteChatLine(char *buffer, size_t size, unsigned int pos);
 
+extern void Irc_SetLastChannel(const char *value);
+extern const char* Irc_GetLastChannel();
+extern void Irc_SendMessage(const char *msg);
+
 static void
 Key_Message (int key, int ascii)
 {
@@ -1201,10 +1205,19 @@ Key_Message (int key, int ascii)
        {
                if(chat_mode < 0)
                        Cmd_ExecuteString(chat_buffer, src_command); // not Cbuf_AddText to allow semiclons in args; however, this allows no variables then. Use aliases!
+               else if(chat_mode == 2)
+                       Irc_SetLastChannel(chat_buffer);
+               else if(chat_mode == 3)
+                       Irc_SendMessage(chat_buffer);
                else
                        Cmd_ForwardStringToServer(va("%s %s", chat_mode ? "say_team" : "say ", chat_buffer));
 
-               key_dest = key_game;
+               //after IRC target input, go to message input
+               if(chat_mode != 2)
+                       key_dest = key_game;
+               else
+                       chat_mode = 3;
+                       
                chat_bufferlen = 0;
                chat_buffer[0] = 0;
                return;
index dd55442a6b02be277ce1d47d08d83582accc6bdb..fc63f7d41fd9ebdaa682ec3a901da2d6b8cf55bf 100644 (file)
@@ -177,7 +177,8 @@ OBJ_COMMON= \
        view.o \
        wad.o \
        world.o \
-       zone.o
+       zone.o \
+       irc.o
 
 # note that builddate.c is very intentionally not compiled to a .o before
 # being linked, because it should be recompiled every time an executable is
@@ -211,7 +212,7 @@ DO_CC=$(CC) $(CFLAGS) -c $< -o $@
 # Link
 LDFLAGS_DEBUG=-g -ggdb $(OPTIM_DEBUG) -DSVNREVISION=`{ test -d .svn && svnversion; } || { test -d .git && git describe --always; } || echo -` -DBUILDTYPE=debug
 LDFLAGS_PROFILE=-g -pg -fprofile-arcs $(OPTIM_RELEASE) -DSVNREVISION=`{ test -d .svn && svnversion; } || { test -d .git && git describe --always; } || echo -` -DBUILDTYPE=profile
-LDFLAGS_RELEASE=$(OPTIM_RELEASE) -DSVNREVISION=`{ test -d .svn && svnversion; } || { test -d .git && git describe --always; } || echo -` -DBUILDTYPE=release
+LDFLAGS_RELEASE=$(OPTIM_RELEASE) -DSVNREVISION=`{ test -d .svn && svnversion; } || { test -d .git && git describe --always; } || echo -` -DBUILDTYPE=release -lircclient
 
 
 ##### UNIX specific variables #####