source: irc_commands.c @ f5d1b31

Last change on this file since f5d1b31 was 565a1ea, checked in by Wilmer van der Gaast <wilmer@…>, at 2008-06-29T09:35:41Z

Added the DEAF command, which makes the daemon stop listening for new
connections. This makes it easier to upgrade a BitlBee without having
to disconnect all current users immediately. Closes #428.

  • Property mode set to 100644
File size: 18.5 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2006 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* IRC commands                                                         */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#define BITLBEE_CORE
27#include "bitlbee.h"
28#include "ipc.h"
29
30static void irc_cmd_pass( irc_t *irc, char **cmd )
31{
32        if( irc->status & USTATUS_LOGGED_IN )
33        {
34                char *send_cmd[] = { "identify", cmd[1], NULL };
35               
36                /* We're already logged in, this client seems to send the PASS
37                   command last. (Possibly it won't send it at all if it turns
38                   out we don't require it, which will break this feature.)
39                   Try to identify using the given password. */
40                return root_command( irc, send_cmd );
41        }
42        /* Handling in pre-logged-in state, first see if this server is
43           password-protected: */
44        else if( global.conf->auth_pass &&
45            ( strncmp( global.conf->auth_pass, "md5:", 4 ) == 0 ?
46                md5_verify_password( cmd[1], global.conf->auth_pass + 4 ) == 0 :
47                strcmp( cmd[1], global.conf->auth_pass ) == 0 ) )
48        {
49                irc->status |= USTATUS_AUTHORIZED;
50                irc_check_login( irc );
51        }
52        else if( global.conf->auth_pass )
53        {
54                irc_reply( irc, 464, ":Incorrect password" );
55        }
56        else
57        {
58                /* Remember the password and try to identify after USER/NICK. */
59                irc_setpass( irc, cmd[1] );
60                irc_check_login( irc );
61        }
62}
63
64static void irc_cmd_user( irc_t *irc, char **cmd )
65{
66        irc->user = g_strdup( cmd[1] );
67        irc->realname = g_strdup( cmd[4] );
68       
69        irc_check_login( irc );
70}
71
72static void irc_cmd_nick( irc_t *irc, char **cmd )
73{
74        if( irc->nick )
75        {
76                irc_reply( irc, 438, ":The hand of the deity is upon thee, thy nick may not change" );
77        }
78        /* This is not clean, but for now it'll have to be like this... */
79        else if( ( nick_cmp( cmd[1], irc->mynick ) == 0 ) || ( nick_cmp( cmd[1], NS_NICK ) == 0 ) )
80        {
81                irc_reply( irc, 433, ":This nick is already in use" );
82        }
83        else if( !nick_ok( cmd[1] ) )
84        {
85                /* [SH] Invalid characters. */
86                irc_reply( irc, 432, ":This nick contains invalid characters" );
87        }
88        else
89        {
90                irc->nick = g_strdup( cmd[1] );
91               
92                irc_check_login( irc );
93        }
94}
95
96static void irc_cmd_quit( irc_t *irc, char **cmd )
97{
98        if( cmd[1] && *cmd[1] )
99                irc_abort( irc, 0, "Quit: %s", cmd[1] );
100        else
101                irc_abort( irc, 0, "Leaving..." );
102}
103
104static void irc_cmd_ping( irc_t *irc, char **cmd )
105{
106        irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost );
107}
108
109static void irc_cmd_oper( irc_t *irc, char **cmd )
110{
111        if( global.conf->oper_pass &&
112            ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ?
113                md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 :
114                strcmp( cmd[2], global.conf->oper_pass ) == 0 ) )
115        {
116                irc_umode_set( irc, "+o", 1 );
117                irc_reply( irc, 381, ":Password accepted" );
118        }
119        else
120        {
121                irc_reply( irc, 432, ":Incorrect password" );
122        }
123}
124
125static void irc_cmd_mode( irc_t *irc, char **cmd )
126{
127        if( *cmd[1] == '#' || *cmd[1] == '&' )
128        {
129                if( cmd[2] )
130                {
131                        if( *cmd[2] == '+' || *cmd[2] == '-' )
132                                irc_reply( irc, 477, "%s :Can't change channel modes", cmd[1] );
133                        else if( *cmd[2] == 'b' )
134                                irc_reply( irc, 368, "%s :No bans possible", cmd[1] );
135                }
136                else
137                        irc_reply( irc, 324, "%s +%s", cmd[1], CMODE );
138        }
139        else
140        {
141                if( nick_cmp( cmd[1], irc->nick ) == 0 )
142                {
143                        if( cmd[2] )
144                                irc_umode_set( irc, cmd[2], 0 );
145                        else
146                                irc_reply( irc, 221, "+%s", irc->umode );
147                }
148                else
149                        irc_reply( irc, 502, ":Don't touch their modes" );
150        }
151}
152
153static void irc_cmd_names( irc_t *irc, char **cmd )
154{
155        irc_names( irc, cmd[1]?cmd[1]:irc->channel );
156}
157
158static void irc_cmd_part( irc_t *irc, char **cmd )
159{
160        struct groupchat *c;
161       
162        if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
163        {
164                user_t *u = user_find( irc, irc->nick );
165               
166                /* Not allowed to leave control channel */
167                irc_part( irc, u, irc->channel );
168                irc_join( irc, u, irc->channel );
169        }
170        else if( ( c = irc_chat_by_channel( irc, cmd[1] ) ) )
171        {
172                user_t *u = user_find( irc, irc->nick );
173               
174                irc_part( irc, u, c->channel );
175               
176                if( c->ic )
177                {
178                        c->joined = 0;
179                        c->ic->acc->prpl->chat_leave( c );
180                }
181        }
182        else
183        {
184                irc_reply( irc, 403, "%s :No such channel", cmd[1] );
185        }
186}
187
188static void irc_cmd_join( irc_t *irc, char **cmd )
189{
190        if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
191                ; /* Dude, you're already there...
192                     RFC doesn't have any reply for that though? */
193        else if( cmd[1] )
194        {
195                if( ( cmd[1][0] == '#' || cmd[1][0] == '&' ) && cmd[1][1] )
196                {
197                        user_t *u = user_find( irc, cmd[1] + 1 );
198                       
199                        if( u && u->ic && u->ic->acc->prpl->chat_with )
200                        {
201                                irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] );
202                               
203                                if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) )
204                                {
205                                        irc_usermsg( irc, "Could not open a groupchat with %s.", u->nick );
206                                }
207                        }
208                        else if( u )
209                        {
210                                irc_reply( irc, 403, "%s :Groupchats are not possible with %s", cmd[1], cmd[1]+1 );
211                        }
212                        else
213                        {
214                                irc_reply( irc, 403, "%s :No such nick", cmd[1] );
215                        }
216                }
217                else
218                {
219                        irc_reply( irc, 403, "%s :No such channel", cmd[1] );
220                }
221        }
222}
223
224static void irc_cmd_invite( irc_t *irc, char **cmd )
225{
226        char *nick = cmd[1], *channel = cmd[2];
227        struct groupchat *c = irc_chat_by_channel( irc, channel );
228        user_t *u = user_find( irc, nick );
229       
230        if( u && c && ( u->ic == c->ic ) )
231                if( c->ic && c->ic->acc->prpl->chat_invite )
232                {
233                        c->ic->acc->prpl->chat_invite( c, u->handle, NULL );
234                        irc_reply( irc, 341, "%s %s", nick, channel );
235                        return;
236                }
237       
238        irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
239}
240
241static void irc_cmd_privmsg( irc_t *irc, char **cmd )
242{
243        if ( !cmd[2] ) 
244        {
245                irc_reply( irc, 412, ":No text to send" );
246        }
247        else if ( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 ) 
248        {
249                irc_write( irc, ":%s!%s@%s %s %s :%s", irc->nick, irc->user, irc->host, cmd[0], cmd[1], cmd[2] ); 
250        }
251        else 
252        {
253                if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
254                {
255                        unsigned int i;
256                        char *t = set_getstr( &irc->set, "default_target" );
257                       
258                        if( g_strcasecmp( t, "last" ) == 0 && irc->last_target )
259                                cmd[1] = irc->last_target;
260                        else if( g_strcasecmp( t, "root" ) == 0 )
261                                cmd[1] = irc->mynick;
262                       
263                        for( i = 0; i < strlen( cmd[2] ); i ++ )
264                        {
265                                if( cmd[2][i] == ' ' ) break;
266                                if( cmd[2][i] == ':' || cmd[2][i] == ',' )
267                                {
268                                        cmd[1] = cmd[2];
269                                        cmd[2] += i;
270                                        *cmd[2] = 0;
271                                        while( *(++cmd[2]) == ' ' );
272                                        break;
273                                }
274                        }
275                       
276                        irc->is_private = 0;
277                       
278                        if( cmd[1] != irc->last_target )
279                        {
280                                g_free( irc->last_target );
281                                irc->last_target = g_strdup( cmd[1] );
282                        }
283                }
284                else
285                {
286                        irc->is_private = 1;
287                }
288                irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? OPT_AWAY : 0 );
289        }
290}
291
292static void irc_cmd_who( irc_t *irc, char **cmd )
293{
294        char *channel = cmd[1];
295        user_t *u = irc->users;
296        struct groupchat *c;
297        GList *l;
298       
299        if( !channel || *channel == '0' || *channel == '*' || !*channel )
300                while( u )
301                {
302                        irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", u->online ? irc->channel : "*", u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
303                        u = u->next;
304                }
305        else if( g_strcasecmp( channel, irc->channel ) == 0 )
306                while( u )
307                {
308                        if( u->online )
309                                irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
310                        u = u->next;
311                }
312        else if( ( c = irc_chat_by_channel( irc, channel ) ) )
313                for( l = c->in_room; l; l = l->next )
314                {
315                        if( ( u = user_findhandle( c->ic, l->data ) ) )
316                                irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
317                }
318        else if( ( u = user_find( irc, channel ) ) )
319                irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
320       
321        irc_reply( irc, 315, "%s :End of /WHO list", channel?channel:"**" );
322}
323
324static void irc_cmd_userhost( irc_t *irc, char **cmd )
325{
326        user_t *u;
327        int i;
328       
329        /* [TV] Usable USERHOST-implementation according to
330                RFC1459. Without this, mIRC shows an error
331                while connecting, and the used way of rejecting
332                breaks standards.
333        */
334       
335        for( i = 1; cmd[i]; i ++ )
336                if( ( u = user_find( irc, cmd[i] ) ) )
337                {
338                        if( u->online && u->away )
339                                irc_reply( irc, 302, ":%s=-%s@%s", u->nick, u->user, u->host );
340                        else
341                                irc_reply( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host );
342                }
343}
344
345static void irc_cmd_ison( irc_t *irc, char **cmd )
346{
347        user_t *u;
348        char buff[IRC_MAX_LINE];
349        int lenleft, i;
350       
351        buff[0] = '\0';
352       
353        /* [SH] Leave room for : and \0 */
354        lenleft = IRC_MAX_LINE - 2;
355       
356        for( i = 1; cmd[i]; i ++ )
357        {
358                char *this, *next;
359               
360                this = cmd[i];
361                while( *this )
362                {
363                        if( ( next = strchr( this, ' ' ) ) )
364                                *next = 0;
365                       
366                        if( ( u = user_find( irc, this ) ) && u->online )
367                        {
368                                lenleft -= strlen( u->nick ) + 1;
369                               
370                                if( lenleft < 0 )
371                                        break;
372                               
373                                strcat( buff, u->nick );
374                                strcat( buff, " " );
375                        }
376                       
377                        if( next )
378                        {
379                                *next = ' ';
380                                this = next + 1;
381                        }
382                        else
383                        {
384                                break;
385                        }   
386                }
387               
388                /* *sigh* */
389                if( lenleft < 0 )
390                        break;
391        }
392       
393        if( strlen( buff ) > 0 )
394                buff[strlen(buff)-1] = '\0';
395       
396        irc_reply( irc, 303, ":%s", buff );
397}
398
399static void irc_cmd_watch( irc_t *irc, char **cmd )
400{
401        int i;
402       
403        /* Obviously we could also mark a user structure as being
404           watched, but what if the WATCH command is sent right
405           after connecting? The user won't exist yet then... */
406        for( i = 1; cmd[i]; i ++ )
407        {
408                char *nick;
409                user_t *u;
410               
411                if( !cmd[i][0] || !cmd[i][1] )
412                        break;
413               
414                nick = g_strdup( cmd[i] + 1 );
415                nick_lc( nick );
416               
417                u = user_find( irc, nick );
418               
419                if( cmd[i][0] == '+' )
420                {
421                        if( !g_hash_table_lookup( irc->watches, nick ) )
422                                g_hash_table_insert( irc->watches, nick, nick );
423                       
424                        if( u && u->online )
425                                irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "is online" );
426                        else
427                                irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", (int) time( NULL ), "is offline" );
428                }
429                else if( cmd[i][0] == '-' )
430                {
431                        gpointer okey, ovalue;
432                       
433                        if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) )
434                        {
435                                g_free( okey );
436                                g_hash_table_remove( irc->watches, okey );
437                               
438                                irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
439                        }
440                }
441        }
442}
443
444static void irc_cmd_topic( irc_t *irc, char **cmd )
445{
446        char *channel = cmd[1];
447        char *topic = cmd[2];
448       
449        if( topic )
450        {
451                /* Send the topic */
452                struct groupchat *c = irc_chat_by_channel( irc, channel );
453                if( c && c->ic && c->ic->acc->prpl->chat_topic )
454                        c->ic->acc->prpl->chat_topic( c, topic );
455        }
456        else
457        {
458                /* Get the topic */
459                irc_topic( irc, channel );
460        }
461}
462
463static void irc_cmd_away( irc_t *irc, char **cmd )
464{
465        user_t *u = user_find( irc, irc->nick );
466        char *away = cmd[1];
467        account_t *a;
468       
469        if( !u ) return;
470       
471        if( away && *away )
472        {
473                int i, j;
474               
475                /* Copy away string, but skip control chars. Mainly because
476                   Jabber really doesn't like them. */
477                u->away = g_malloc( strlen( away ) + 1 );
478                for( i = j = 0; away[i]; i ++ )
479                        if( ( u->away[j] = away[i] ) >= ' ' )
480                                j ++;
481                u->away[j] = 0;
482               
483                irc_reply( irc, 306, ":You're now away: %s", u->away );
484                /* irc_umode_set( irc, irc->myhost, "+a" ); */
485        }
486        else
487        {
488                if( u->away ) g_free( u->away );
489                u->away = NULL;
490                /* irc_umode_set( irc, irc->myhost, "-a" ); */
491                irc_reply( irc, 305, ":Welcome back" );
492        }
493       
494        for( a = irc->accounts; a; a = a->next )
495        {
496                struct im_connection *ic = a->ic;
497               
498                if( ic && ic->flags & OPT_LOGGED_IN )
499                        imc_set_away( ic, u->away );
500        }
501}
502
503static void irc_cmd_whois( irc_t *irc, char **cmd )
504{
505        char *nick = cmd[1];
506        user_t *u = user_find( irc, nick );
507       
508        if( u )
509        {
510                irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname );
511               
512                if( u->ic )
513                        irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->ic->acc->user,
514                                   u->ic->acc->server && *u->ic->acc->server ? u->ic->acc->server : "",
515                                   u->ic->acc->prpl->name );
516                else
517                        irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO );
518               
519                if( !u->online )
520                        irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
521                else if( u->away )
522                        irc_reply( irc, 301, "%s :%s", u->nick, u->away );
523               
524                irc_reply( irc, 318, "%s :End of /WHOIS list", nick );
525        }
526        else
527        {
528                irc_reply( irc, 401, "%s :Nick does not exist", nick );
529        }
530}
531
532static void irc_cmd_whowas( irc_t *irc, char **cmd )
533{
534        /* For some reason irssi tries a whowas when whois fails. We can
535           ignore this, but then the user never gets a "user not found"
536           message from irssi which is a bit annoying. So just respond
537           with not-found and irssi users will get better error messages */
538       
539        irc_reply( irc, 406, "%s :Nick does not exist", cmd[1] );
540        irc_reply( irc, 369, "%s :End of WHOWAS", cmd[1] );
541}
542
543static void irc_cmd_nickserv( irc_t *irc, char **cmd )
544{
545        /* [SH] This aliases the NickServ command to PRIVMSG root */
546        /* [TV] This aliases the NS command to PRIVMSG root as well */
547        root_command( irc, cmd + 1 );
548}
549
550static void irc_cmd_motd( irc_t *irc, char **cmd )
551{
552        irc_motd( irc );
553}
554
555static void irc_cmd_pong( irc_t *irc, char **cmd )
556{
557        /* We could check the value we get back from the user, but in
558           fact we don't care, we're just happy he's still alive. */
559        irc->last_pong = gettime();
560        irc->pinging = 0;
561}
562
563static void irc_cmd_version( irc_t *irc, char **cmd )
564{
565        irc_reply( irc, 351, "bitlbee-%s. %s :%s/%s ", BITLBEE_VERSION, irc->myhost, ARCH, CPU );
566}
567
568static void irc_cmd_completions( irc_t *irc, char **cmd )
569{
570        user_t *u = user_find( irc, irc->mynick );
571        help_t *h;
572        set_t *s;
573        int i;
574       
575        irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" );
576       
577        for( i = 0; commands[i].command; i ++ )
578                irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command );
579       
580        for( h = global.help; h; h = h->next )
581                irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->title );
582       
583        for( s = irc->set; s; s = s->next )
584                irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS set ", s->key );
585       
586        irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "END" );
587}
588
589static void irc_cmd_rehash( irc_t *irc, char **cmd )
590{
591        if( global.conf->runmode == RUNMODE_INETD )
592                ipc_master_cmd_rehash( NULL, NULL );
593        else
594                ipc_to_master( cmd );
595       
596        irc_reply( irc, 382, "%s :Rehashing", global.conf_file );
597}
598
599static const command_t irc_commands[] = {
600        { "pass",        1, irc_cmd_pass,        0 },
601        { "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
602        { "nick",        1, irc_cmd_nick,        0 },
603        { "quit",        0, irc_cmd_quit,        0 },
604        { "ping",        0, irc_cmd_ping,        0 },
605        { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
606        { "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
607        { "names",       0, irc_cmd_names,       IRC_CMD_LOGGED_IN },
608        { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
609        { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
610        { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
611        { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
612        { "notice",      1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
613        { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
614        { "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
615        { "ison",        1, irc_cmd_ison,        IRC_CMD_LOGGED_IN },
616        { "watch",       1, irc_cmd_watch,       IRC_CMD_LOGGED_IN },
617        { "topic",       1, irc_cmd_topic,       IRC_CMD_LOGGED_IN },
618        { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
619        { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
620        { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
621        { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
622        { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
623        { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
624        { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
625        { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
626        { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
627        { "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
628        { "deaf",        0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
629        { "wallops",     1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
630        { "wall",        1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
631        { "rehash",      0, irc_cmd_rehash,      IRC_CMD_OPER_ONLY },
632        { "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
633        { "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
634        { NULL }
635};
636
637void irc_exec( irc_t *irc, char *cmd[] )
638{       
639        int i, n_arg;
640       
641        if( !cmd[0] )
642                return;
643       
644        for( i = 0; irc_commands[i].command; i++ )
645                if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 )
646                {
647                        /* There should be no typo in the next line: */
648                        for( n_arg = 0; cmd[n_arg]; n_arg ++ ); n_arg --;
649                       
650                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
651                        {
652                                irc_reply( irc, 462, ":Only allowed before logging in" );
653                        }
654                        else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
655                        {
656                                irc_reply( irc, 451, ":Register first" );
657                        }
658                        else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
659                        {
660                                irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" );
661                        }
662                        else if( n_arg < irc_commands[i].required_parameters )
663                        {
664                                irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
665                        }
666                        else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
667                        {
668                                /* IPC doesn't make sense in inetd mode,
669                                    but the function will catch that. */
670                                ipc_to_master( cmd );
671                        }
672                        else
673                        {
674                                irc_commands[i].execute( irc, cmd );
675                        }
676                       
677                        return;
678                }
679       
680        if( irc->status >= USTATUS_LOGGED_IN )
681                irc_reply( irc, 421, "%s :Unknown command", cmd[0] );
682}
Note: See TracBrowser for help on using the repository browser.