]> git.xonotic.org Git - xonotic/darkplaces.git/blob - irc.c
Merge remote branch 'origin/master' into akari/irc
[xonotic/darkplaces.git] / irc.c
1 //      irc.c
2 //      
3 //      Copyright 2011 Akari <Akari` @ irc.quakenet.org>
4 //      
5 //      This program is free software; you can redistribute it and/or modify
6 //      it under the terms of the GNU General Public License as published by
7 //      the Free Software Foundation; either version 2 of the License, or
8 //      (at your option) any later version.
9 //      
10 //      This program is distributed in the hope that it will be useful,
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //      GNU General Public License for more details.
14
15 #include <pthread.h>
16 #include <string.h>
17
18 #include "quakedef.h"
19 #include "irc.h"
20 #include "cvar.h"
21
22 cvar_t irc_server = {CVAR_SAVE, "irc_server", "", "IRC server to connect to"};
23 cvar_t irc_port = {CVAR_SAVE, "irc_port", "6667", "Port of the IRC server"};
24 cvar_t irc_password = {CVAR_SAVE, "irc_password", "", "IRC server password"};
25 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"};
26 cvar_t irc_connected = {CVAR_READONLY, "irc_connected", "0", "IRC connection state (0 = not connected, 1 = connecting, 2 = connected, 3 = disconnecting)"};
27 cvar_t irc_msgprefix = {CVAR_SAVE, "irc_msgprefix", "^5IRC^0|^7", "What all IRC events will be prefixed with when printed to the console"};
28 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"};
29 cvar_t irc_numeric_errorsonly = {CVAR_SAVE, "irc_numeric_errorsonly", "0", "If 1, any numeric event below 400 won't be printed'"};
30 cvar_t irc_save_target = {CVAR_SAVE, "irc_save_target", "1", "Whether to save target for irc_messagemode or not"};
31 cvar_t irc_current_nick = {CVAR_READONLY, "irc_current_nick", "", "Holds your current IRC nick"};
32 cvar_t irc_hilights = {CVAR_SAVE, "irc_hilights", "", "Space separated list of words to hilight"};
33 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"};
34 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"};
35
36 irc_session_t *irc_session_global = NULL;
37 int irc_msgmode;
38 char last_channel[MAX_INPUTLINE];
39
40 //
41 //  Initialization
42 //
43
44 void CL_Irc_Init(void)
45 {
46     Cvar_RegisterVariable(&irc_server);
47     Cvar_RegisterVariable(&irc_port);
48     Cvar_RegisterVariable(&irc_password);
49     Cvar_RegisterVariable(&irc_nick);
50     Cvar_RegisterVariable(&irc_connected);
51     Cvar_RegisterVariable(&irc_msgprefix);
52     Cvar_RegisterVariable(&irc_chatwindow);
53     Cvar_RegisterVariable(&irc_numeric_errorsonly);
54     Cvar_RegisterVariable(&irc_save_target);
55     Cvar_RegisterVariable(&irc_current_nick);
56     Cvar_RegisterVariable(&irc_hilights);
57     Cvar_RegisterVariable(&irc_autochangetarget);
58     Cvar_RegisterVariable(&irc_watched_channels);
59     
60     Cmd_AddCommand ("irc_connect", CL_Irc_Connect_f, "Connects you to the IRC server");
61     Cmd_AddCommand ("irc_disconnect", CL_Irc_Disconnect_f, "Disconnects you from the IRC server");
62     Cmd_AddCommand ("irc_say", CL_Irc_Say_f, "Sends a privmsg to a channel or nick");
63     Cmd_AddCommand ("irc_notice", CL_Irc_Notice_f, "Sends a notice to a channel or nick");
64     Cmd_AddCommand ("irc_me", CL_Irc_Me_f, "Sends a CTCP ACTION (/me) to a channel or nick");
65     Cmd_AddCommand ("irc_join", CL_Irc_Join_f, "Joins an IRC channel");
66     Cmd_AddCommand ("irc_part", CL_Irc_Part_f, "Parts an IRC channel");
67     Cmd_AddCommand ("irc_names", CL_Irc_Names_f, "Lists users of an IRC channel");
68     Cmd_AddCommand ("irc_messagemode", CL_Irc_MessageMode_f, "Interactive prompt for sending IRC messages. Meant to be bound to a key");
69     Cmd_AddCommand ("irc_chnick", CL_Irc_ChNick_f, "Changes your nick");
70     Cmd_AddCommand ("irc_raw", CL_Irc_Raw_f, "Sends a raw string to the IRC server");
71 }
72
73 //
74 //  Function that starts IRC main loop in a thread
75 //
76
77 static void IRC_Thread(void *p)
78 {
79     if(irc_run(irc_session_global))
80     {
81         if(irc_connected.integer == 3) //irc_disconnect
82         {
83             Cvar_SetQuick(&irc_connected, "0");
84             return;
85         }
86         
87         Con_Printf("%s^1Error: ^7%s\n",
88             irc_msgprefix.string,
89             irc_strerror(irc_errno(irc_session_global))
90         );
91         
92         CL_Irc_Disconnect_f();
93         return;
94     }
95 }
96
97 //
98 //  irc_ console commands callbacks
99 //
100
101 static void CL_Irc_Connect_f(void)
102 {
103     irc_callbacks_t cb;
104     pthread_t irc_thread;
105     
106     switch(irc_connected.integer)
107     {
108         case 1:
109             Con_Printf("%sAlready connecting to %s:%i\n",
110                 irc_msgprefix.string, 
111                 irc_server.string,
112                 irc_port.integer
113             );
114             return;
115         
116         case 2:
117             Con_Printf("%sAlready connected to %s:%i.\n",
118                 irc_msgprefix.string,
119                 irc_server.string,
120                 irc_port.integer
121             );
122             return;
123     }
124     
125     if(NOTSET(irc_server))
126     {
127         Con_Printf("Please set the irc_server variable\n");
128         return;
129     }
130     
131     if(NOTSET(irc_nick))
132     {
133         Con_Printf("Please set the irc_nick variable\n");
134         return;
135     }
136     
137     if(NOTSET(irc_port))
138     {
139         Con_Printf("Please set the irc_port variable\n");
140         return;
141     }
142     
143     Cvar_SetQuick(&irc_connected, "1");
144     
145     memset(&cb, 0, sizeof(cb));
146     cb.event_connect = event_connect;
147     cb.event_numeric = event_numeric;
148     cb.event_privmsg = event_privmsg;
149     cb.event_channel = event_channel;
150     cb.event_nick    = event_nick;
151     cb.event_quit    = event_quit;
152     cb.event_join    = event_join;
153     cb.event_part    = event_part;
154     cb.event_mode    = event_mode;
155     cb.event_umode   = event_umode;
156     cb.event_topic   = event_topic;
157     cb.event_kick    = event_kick;
158     cb.event_notice  = event_notice;
159     cb.event_invite  = event_invite;
160     cb.event_ctcp_action = event_ctcp_action;
161
162     Cvar_SetQuick(&irc_current_nick, irc_nick.string);
163
164     irc_session_global = irc_create_session(&cb);
165     irc_option_set(irc_session_global, LIBIRC_OPTION_STRIPNICKS);
166     if(irc_connect(
167         irc_session_global,
168         irc_server.string,
169         irc_port.integer,
170         NOTSET(irc_password)? NULL : irc_password.string,
171         irc_nick.string,
172         "dpirc", "DPIRC user"
173     ))
174     {   //Connection failed
175         Con_Printf("%s^1Connection failed: ^7%s\n",
176             irc_msgprefix.string,
177             irc_strerror(irc_errno(irc_session_global))
178         );
179         
180         CL_Irc_Disconnect_f();
181         return;
182     }
183     
184     pthread_create (&irc_thread, NULL, (void *) &IRC_Thread, NULL);
185 }
186
187 static void CL_Irc_Disconnect_f(void)
188 {
189     if(!irc_connected.integer)
190     {
191         Con_Printf("%sNot connected\n",
192             irc_msgprefix.string
193         );
194         
195         return;
196     }
197     
198     Con_Printf("^1Disconnected from the IRC server\n");
199     Cvar_SetQuick(&irc_connected, "3");
200     irc_cmd_quit(irc_session_global, "Disconnected");
201     irc_destroy_session(irc_session_global);
202 }
203
204 static void CL_Irc_Say_Universal_f(void)
205 {
206     int cmdlen, i, j, space;
207     const char *cmd, *dest;
208     char message[MAX_INPUTLINE];
209     qboolean watched;
210
211     if(Cmd_Argc() < 3) switch(irc_msgmode)
212     {
213         case MSGMODE_PRIVMSG:
214             Con_Printf("Usage: irc_say channel_or_nick message\n");
215             return;
216         case MSGMODE_NOTICE:
217             Con_Printf("Usage: irc_notice channel_or_nick message\n");
218             return;
219         case MSGMODE_ACTION:
220             Con_Printf("Usage: irc_me channel_or_nick message\n");
221             return;
222     }
223     
224     cmd = Cmd_Args();
225     cmdlen = strlen(cmd);
226     
227     space = 0;
228     for(i = 0, j = 0; i < cmdlen; ++i)
229     {
230         if(space)
231         {
232             message[j++] = cmd[i];
233         }
234         else if(cmd[i] == ' ') ++space;
235     }
236     
237     message[j] = '\0';
238     
239     dest = Cmd_Argv(1);
240     
241     switch(irc_msgmode)
242     {
243         case MSGMODE_PRIVMSG:
244             irc_cmd_msg(irc_session_global, dest, message);
245             watched = Irc_IsWatchedChannel(dest);
246             
247             if(ISCHANNEL(dest)) Con_Printf("%s%s^3%s^0|^7<^2%s^7> %s\n",
248                 watched? "\001" : CHATWINDOW,
249                 irc_msgprefix.string,
250                 dest,
251                 irc_current_nick.string,
252                 message
253             ); else Con_Printf("%s%s^1Privmsg to ^2%s^7: ^3%s\n",
254                 CHATWINDOW_URGENT,
255                 irc_msgprefix.string,
256                 dest,
257                 message
258             );
259             
260             break;
261         
262         case MSGMODE_NOTICE:
263             irc_cmd_notice(irc_session_global, dest, message);
264             
265             if(!ISCHANNEL(dest)) Con_Printf("%s%sNotice to ^2%s^7: ^9%s\n",
266                 CHATWINDOW,
267                 irc_msgprefix.string,
268                 dest,
269                 message
270             ); else Con_Printf("%s%s^3%s^0|^9-^2%s^9- %s\n",
271                 CHATWINDOW,
272                 irc_msgprefix.string,
273                 dest,
274                 irc_current_nick.string,
275                 message
276             );
277             
278             break;
279         
280         case MSGMODE_ACTION:
281             irc_cmd_me(irc_session_global, dest, message);
282             
283             if(ISCHANNEL(dest)) Con_Printf("%s%s^3%s^0| ^2* %s ^7%s\n",
284                 watched? "\001" : CHATWINDOW,
285                 irc_msgprefix.string,
286                 dest,
287                 irc_current_nick.string,
288                 message
289             ); else Con_Printf("%s%s^1Privmsg to ^2%s^7: ^2* %s ^3%s\n",
290                 CHATWINDOW_URGENT,
291                 irc_msgprefix.string,
292                 dest,
293                 irc_current_nick.string,
294                 message
295             );
296             break;
297     }
298 }
299
300 static void CL_Irc_Raw_f(void)
301 {
302     if(Cmd_Argc() < 2)
303     {
304         Con_Printf("Usage: irc_raw command\n");
305         return;
306     }
307     
308     irc_send_raw(irc_session_global, "%s", Cmd_Args());
309 }
310
311 static void CL_Irc_Say_f(void)
312 {
313     MUSTCONNECT
314     irc_msgmode = MSGMODE_PRIVMSG;
315     CL_Irc_Say_Universal_f();
316 }
317
318 static void CL_Irc_Notice_f(void)
319 {
320     MUSTCONNECT
321     irc_msgmode = MSGMODE_NOTICE;
322     CL_Irc_Say_Universal_f();
323 }
324
325 static void CL_Irc_Me_f(void)
326 {
327     MUSTCONNECT
328     irc_msgmode = MSGMODE_ACTION;
329     CL_Irc_Say_Universal_f();
330 }
331
332 static void CL_Irc_Join_f(void)
333 {
334     int argc = Cmd_Argc();
335     const char *channel;
336     
337     MUSTCONNECT
338     
339     if(argc < 2)
340     {
341         Con_Printf("Usage: irc_join channel [key]\n");
342         return;
343     }
344     
345     channel = Cmd_Argv(1);
346     
347     if(argc > 2)
348         irc_cmd_join(irc_session_global, channel, Cmd_Argv(2));
349     else
350         irc_cmd_join(irc_session_global, channel, NULL);
351 }
352
353 static void CL_Irc_Part_f(void)
354 {
355     MUSTCONNECT
356     
357     if(Cmd_Argc() < 2)
358     {
359         Con_Printf("Usage: irc_part channel\n");
360         return;
361     }
362     
363     irc_cmd_part(irc_session_global, Cmd_Argv(1));
364 }
365
366 static void CL_Irc_Names_f(void)
367 {
368     MUSTCONNECT
369     
370     if(Cmd_Argc() < 2)
371     {
372         Con_Printf("Usage: irc_names channel\n");
373         return;
374     }
375     
376     irc_cmd_names(irc_session_global, Cmd_Argv(1));
377 }
378
379 void CL_Irc_MessageMode_f(void)
380 {
381     const char *tmp;
382     
383     key_dest = key_message;
384     chat_mode = 2;
385     chat_bufferlen = 0;
386     chat_buffer[0] = 0;
387     
388     if(irc_save_target.integer)
389     {
390         tmp = Irc_GetLastChannel();
391         strlcpy(chat_buffer, tmp, sizeof(chat_buffer));
392         chat_bufferlen = strlen(chat_buffer);
393     }
394 }
395
396 void CL_Irc_ChNick_f(void)
397 {
398     MUSTCONNECT
399     
400     if(Cmd_Argc() < 2)
401     {
402         Con_Printf("Usage: irc_chnick nick\n");
403         return;
404     }
405     
406     irc_cmd_nick(irc_session_global, Cmd_Argv(1));
407 }
408
409
410 void Irc_SetLastChannel(const char *value)
411 {
412     strlcpy(last_channel, value, sizeof(last_channel));
413 }
414
415 const char* Irc_GetLastChannel(void)
416 {
417     return last_channel;
418 }
419
420
421 void Irc_SendMessage(const char *message)
422 {
423     const char* dest = Irc_GetLastChannel();
424     qboolean watched = Irc_IsWatchedChannel(dest);
425     
426     MUSTCONNECT
427     
428     irc_cmd_msg(irc_session_global, dest, message);
429             
430     if(ISCHANNEL(dest)) Con_Printf("%s%s^3%s^0|^7<^2%s^7> %s\n",
431         watched? "\001" : CHATWINDOW,
432         irc_msgprefix.string,
433         dest,
434         irc_current_nick.string,
435         message
436     ); else Con_Printf("%s%s^1Privmsg to ^2%s^7: ^3%s\n",
437         CHATWINDOW_URGENT,
438         irc_msgprefix.string,
439         dest,
440         message
441     );
442 }
443
444 //
445 //  IRC events
446 //
447
448 IRCEVENT(event_connect)
449 {
450     Cvar_SetQuick(&irc_connected, "2");
451     Con_Printf("%sConnected to %s:%i\n",
452         irc_msgprefix.string, 
453         irc_server.string,
454         irc_port.integer
455     );
456 }
457
458 IRCNUMEVENT(event_numeric)
459 {
460     //Get our initial nick from the welcome message
461     if(event == 001)
462         Cvar_SetQuick(&irc_current_nick, params[0]);
463     
464     if (!irc_numeric_errorsonly.integer || event > 400)
465     {
466         Con_Printf("%s^3%d ^2%s ^1%s^7 %s %s %s\n",
467             irc_msgprefix.string,
468             event,
469             origin ? origin : "^8(unknown)",
470             params[0],
471             count > 1 ? params[1] : "",
472             count > 2 ? params[2] : "",
473             count > 3 ? params[3] : ""
474         );
475     }
476 }
477
478 IRCEVENT(event_privmsg)
479 {
480     char* msgstr = "";
481     
482     if(count > 1)
483         msgstr = irc_color_strip_from_mirc(params[1]);
484     
485     UPDATETARGET(origin)
486     
487     Con_Printf("%s%s^1Privmsg from ^2%s^7: ^3%s\n",
488         CHATWINDOW_URGENT,
489         irc_msgprefix.string,
490         origin,
491         msgstr
492     );
493     
494     if(count > 1) free(msgstr);
495 }
496
497
498 IRCEVENT(event_channel)
499 {
500     char* msgstr = "";
501     qboolean watched;
502     
503     //weird shit
504     if(!ISCHANNEL(params[0]))
505         return event_privmsg(session, event, origin, params, count);
506     
507     if(count > 1)
508         msgstr = irc_color_strip_from_mirc(params[1]);
509     
510     watched = Irc_IsWatchedChannel(params[0]);
511     
512     if(Irc_CheckHilight(msgstr))
513     {   
514         UPDATETARGET(params[0])
515         
516         Con_Printf("%s%s^3%s^0|^7<^2%s^7> ^1%s\n",
517             watched? "\001" : CHATWINDOW_URGENT,
518             irc_msgprefix.string,
519             params[0],
520             origin,
521             msgstr
522         );
523     }
524     else Con_Printf("%s%s^3%s^0|^7<^2%s^7> %s\n",
525         watched? "\001" : CHATWINDOW,
526         irc_msgprefix.string,
527         params[0],
528         origin,
529         msgstr
530     );
531     
532     if(count > 1) free(msgstr);
533 }
534
535 IRCEVENT(event_nick)
536 {
537     //printf("%sorigin -> %s (%s, %s)\n", origin, params[0], irc_current_nick.string, irc_nick.string);
538     //crash!
539     //cvar_t dumb;
540     //Cvar_SetQuick(&dumb, NULL);
541     
542     if(!strncmp(origin, irc_current_nick.string, 512)) //Our nick is changed
543     {
544         Cvar_SetQuick(&irc_current_nick, params[0]);
545         
546         Con_Printf("%s%s^7Your nick is now ^2%s\n",
547             CHATWINDOW,
548             irc_msgprefix.string,
549             params[0]
550         );
551         
552         return;
553     }
554     
555     Con_Printf("%s%s^2%s^7 is now known as ^2%s\n",
556         CHATWINDOW,
557         irc_msgprefix.string,
558         origin,
559         params[0]
560     );
561 }
562
563 IRCEVENT(event_quit)
564 {
565     Con_Printf("%s%s^2%s^7 has quit IRC: ^2%s\n",
566         CHATWINDOW,
567         irc_msgprefix.string,
568         origin,
569         count? params[0] : "^8(quit message missing)"
570     );
571 }
572
573 IRCEVENT(event_join)
574 {
575     Con_Printf("%s%s^2%s^7 has joined ^3%s\n",
576         CHATWINDOW,
577         irc_msgprefix.string,
578         origin,
579         params[0]
580     );
581 }
582
583 IRCEVENT(event_part)
584 {
585     Con_Printf("%s%s^2%s^7 has left ^3%s^7: %s\n",
586         CHATWINDOW,
587         irc_msgprefix.string,
588         origin,
589         params[0],
590         count > 1? params[1] : "^8(part message missing)"
591     );
592 }
593
594 IRCEVENT(event_mode)
595 {
596     char paramstring[MAX_INPUTLINE] = "";
597     unsigned int i;
598     
599     for(i = 2; i < count; i++)
600     {
601         strlcat(paramstring, params[i], sizeof(paramstring));
602         strlcat(paramstring, " ", sizeof(paramstring));
603     }
604     
605     Con_Printf("%s%s^2%s^7 set mode on ^3%s^7: %s %s\n",
606         CHATWINDOW,
607         irc_msgprefix.string,
608         origin,
609         params[0],
610         params[1],
611         paramstring
612     );
613 }
614
615 IRCEVENT(event_umode)
616 {
617     Con_Printf("%sUsermode changed for ^2%s^7: %s\n",
618         irc_msgprefix.string,
619         origin,
620         params[0]
621     );
622 }
623
624 IRCEVENT(event_topic)
625 {
626     if(count > 1) Con_Printf("%s%s^2%s^7 changed the topic of ^3%s^7: %s\n",
627         CHATWINDOW,
628         irc_msgprefix.string,
629         origin,
630         params[0],
631         params[1]
632     );
633 }
634
635 IRCEVENT(event_kick)
636 {
637     Con_Printf("%s%s^2%s^7 has kicked ^2%s^7 out of ^3%s^7: %s\n",
638         CHATWINDOW,
639         irc_msgprefix.string,
640         origin,
641         count > 1? params[1] : "^8(nick missing)", //libircclient documentation says params[1] is optinal.
642         params[0],
643         count > 2? params[2] : "^8(random kick victim! yay!)"
644     );
645 }
646
647 IRCEVENT(event_notice)
648 {
649     char* msgstr = "";
650     
651     if(count > 1)
652         msgstr = irc_color_strip_from_mirc(params[1]);
653     
654     if(!ISCHANNEL(params[0])) Con_Printf("%s%sNotice from ^2%s^7: ^9%s\n",
655         CHATWINDOW,
656         irc_msgprefix.string,
657         origin,
658         msgstr
659     ); else Con_Printf("%s%s^3%s^0|^9-^2%s^9- %s\n",
660         CHATWINDOW,
661         irc_msgprefix.string,
662         params[0],
663         origin,
664         msgstr
665     );
666     
667     if(count > 1) free(msgstr);
668 }
669
670 IRCEVENT(event_invite)
671 {
672     Con_Printf("%s%s^2%s^7 invites you to ^3%s\n",
673         CHATWINDOW,
674         irc_msgprefix.string,
675         origin,
676         params[1]
677     );
678 }
679
680 IRCEVENT(event_ctcp_action)
681 {
682     char* msgstr = "";
683     qboolean watched;
684     
685     if(!ISCHANNEL(params[0]))
686     {
687         event_ctcp_action_priv(session, event, origin, params, count);
688         return;
689     }
690     
691     if(count > 1)
692         msgstr = irc_color_strip_from_mirc(params[1]);
693     
694     watched = Irc_IsWatchedChannel(params[0]);
695     
696     if(Irc_CheckHilight(msgstr))
697     {   
698         UPDATETARGET(params[0])
699         
700         Con_Printf("%s%s^3%s^0| ^1* %s ^7%s\n",
701             watched? "\001" : CHATWINDOW_URGENT,
702             irc_msgprefix.string,
703             params[0],
704             origin,
705             msgstr
706         );
707     }
708     else Con_Printf("%s%s^3%s^0| ^2* %s ^7%s\n",
709         watched? "\001" : CHATWINDOW,
710         irc_msgprefix.string,
711         params[0],
712         origin,
713         msgstr
714     );
715     
716     if(count > 1) free(msgstr);
717 }
718
719 //called by event_ctcp_action
720 IRCEVENT(event_ctcp_action_priv)
721 {
722     char* msgstr = "";
723     
724     if(count > 1)
725         msgstr = irc_color_strip_from_mirc(params[1]);
726     
727     UPDATETARGET(origin)
728     
729     Con_Printf("%s%s^1Privmsg^7: ^2* %s ^3%s\n",
730         CHATWINDOW_URGENT,
731         irc_msgprefix.string,
732         origin,
733         msgstr
734     );
735     
736     if(count > 1) free(msgstr);
737 }
738
739 //
740 //  Function that checks if a message contains hilights
741 //
742
743 qboolean Irc_CheckHilight(const char *msg)
744 {
745     int start, idx, len;
746     char buffer[512];
747     
748     if(strcasestr(msg, irc_current_nick.string))
749         return TRUE; //Contains our nick
750     
751     if(NOTSET(irc_hilights))
752         return FALSE;
753     
754     len = strlen(irc_hilights.string);
755     start = 0;
756     
757     for(idx = 0; idx < len; ++idx)
758     {
759         if(irc_hilights.string[idx] == ' ')
760         {
761             strlcpy(buffer, irc_hilights.string+start, idx+1);
762             if(strcasestr(msg, buffer))
763                 return TRUE; //Contains a word from hilight list
764                 
765             start = idx+1;
766         }
767     }
768     
769     //Catch the final word
770     strlcpy(buffer, irc_hilights.string+start, idx+1);
771     if(strcasestr(msg, buffer))
772         return TRUE; //Contains a word from hilight list
773     
774     return FALSE;
775 }
776
777 //
778 //  Checks if channel is watched
779 //
780
781 qboolean Irc_IsWatchedChannel(const char* chan)
782 {
783     int start, idx, len;
784     char buffer[512];
785     
786     if(NOTSET(irc_watched_channels))
787         return FALSE;
788     
789     len = strlen(irc_watched_channels.string);
790     start = 0;
791     
792     for(idx = 0; idx < len; ++idx)
793     {
794         if(irc_watched_channels.string[idx] == ' ')
795         {
796             strlcpy(buffer, irc_watched_channels.string+start, idx+1);
797             if(strcasestr(chan, buffer))
798                 return TRUE;
799                 
800             start = idx+1;
801         }
802     }
803     
804     //Catch the final channel
805     strlcpy(buffer, irc_watched_channels.string+start, idx+1);
806     if(strcasestr(chan, buffer))
807         return TRUE;
808     
809     return FALSE;
810 }
811
812 //
813 //  Functions that should have been in libircclient
814 //
815
816 int irc_cmd_nick(irc_session_t * session, const char *nick)
817 {
818     if(!nick)
819     {
820         //session->lasterror = LIBIRC_ERR_STATE; Won't compile
821         return 1;
822     }
823
824     return irc_send_raw(session, "NICK %s", nick);
825 }