source: irc_commands.c @ 4255320

Last change on this file since 4255320 was a7dbf45, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-27T10:27:47Z

Block CTCPs to channels instead of sending them as plain messages. Maybe
some other day I'll find a reason for actually supporting them.

  • Property mode set to 100644
File size: 18.8 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2010 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_send_num( 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->user = g_strdup( cmd[1] );
67        irc->user->fullname = g_strdup( cmd[4] );
68       
69        irc_check_login( irc );
70}
71
72static void irc_cmd_nick( irc_t *irc, char **cmd )
73{
74        irc_user_t *iu;
75       
76        if( ( iu = irc_user_by_name( irc, cmd[1] ) ) && iu != irc->user )
77        {
78                irc_send_num( irc, 433, "%s :This nick is already in use", cmd[1] );
79        }
80        else if( !nick_ok( cmd[1] ) )
81        {
82                /* [SH] Invalid characters. */
83                irc_send_num( irc, 432, "%s :This nick contains invalid characters", cmd[1] );
84        }
85        else if( irc->status & USTATUS_LOGGED_IN )
86        {
87                if( irc->status & USTATUS_IDENTIFIED )
88                {
89                        irc_setpass( irc, NULL );
90                        irc->status &= ~USTATUS_IDENTIFIED;
91                        irc_umode_set( irc, "-R", 1 );
92                        irc_usermsg( irc, "Changing nicks resets your identify status. "
93                                     "Re-identify or register a new account if you want "
94                                     "your configuration to be saved. See \x02help "
95                                     "nick_changes\x02." );
96                }
97               
98                irc_user_set_nick( irc->user, cmd[1] );
99        }
100        else
101        {
102                g_free( irc->user->nick );
103                irc->user->nick = g_strdup( cmd[1] );
104               
105                irc_check_login( irc );
106        }
107}
108
109static void irc_cmd_quit( irc_t *irc, char **cmd )
110{
111        if( cmd[1] && *cmd[1] )
112                irc_abort( irc, 0, "Quit: %s", cmd[1] );
113        else
114                irc_abort( irc, 0, "Leaving..." );
115}
116
117static void irc_cmd_ping( irc_t *irc, char **cmd )
118{
119        irc_write( irc, ":%s PONG %s :%s", irc->root->host,
120                   irc->root->host, cmd[1]?cmd[1]:irc->root->host );
121}
122
123static void irc_cmd_pong( irc_t *irc, char **cmd )
124{
125        /* We could check the value we get back from the user, but in
126           fact we don't care, we're just happy s/he's still alive. */
127        irc->last_pong = gettime();
128        irc->pinging = 0;
129}
130
131static void irc_cmd_join( irc_t *irc, char **cmd )
132{
133        char *comma, *s = cmd[1];
134       
135        while( s )
136        {
137                irc_channel_t *ic;
138               
139                if( ( comma = strchr( s, ',' ) ) )
140                        *comma = '\0';
141               
142                if( ( ic = irc_channel_by_name( irc, s ) ) == NULL )
143                {
144                        ic = irc_channel_new( irc, s );
145                       
146                        if( strcmp( set_getstr( &ic->set, "type" ), "control" ) != 0 )
147                        {
148                                /* Autoconfiguration is for control channels only ATM. */
149                        }
150                        else if( bee_group_by_name( ic->irc->b, ic->name + 1, FALSE ) )
151                        {
152                                set_setstr( &ic->set, "group", ic->name + 1 );
153                                set_setstr( &ic->set, "fill_by", "group" );
154                        }
155                        else if( set_setstr( &ic->set, "protocol", ic->name + 1 ) )
156                        {
157                                set_setstr( &ic->set, "fill_by", "protocol" );
158                        }
159                        else if( set_setstr( &ic->set, "account", ic->name + 1 ) )
160                        {
161                                set_setstr( &ic->set, "fill_by", "account" );
162                        }
163                        else
164                        {
165                                bee_irc_channel_update( ic->irc, ic, NULL );
166                        }
167                }
168               
169                if( ic == NULL )
170                {
171                        irc_send_num( irc, 479, "%s :Invalid channel name", s );
172                        goto next;
173                }
174               
175                if( ic->flags & IRC_CHANNEL_JOINED )
176                        /* Dude, you're already there...
177                           RFC doesn't have any reply for that though? */
178                        goto next;
179               
180                if( ic->f->join && !ic->f->join( ic ) )
181                        /* The story is: FALSE either means the handler
182                           showed an error message, or is doing some work
183                           before the join should be confirmed. (In the
184                           latter case, the caller should take care of that
185                           confirmation.) TRUE means all's good, let the
186                           user join the channel right away. */
187                        goto next;
188               
189                irc_channel_add_user( ic, irc->user );
190               
191next:
192                if( comma )
193                {
194                        s = comma + 1;
195                        *comma = ',';
196                }
197                else
198                        break;
199        }
200}
201
202static void irc_cmd_names( irc_t *irc, char **cmd )
203{
204        irc_channel_t *ic;
205       
206        if( cmd[1] && ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
207                irc_send_names( ic );
208        /* With no args, we should show /names of all chans. Make the code
209           below work well if necessary.
210        else
211        {
212                GSList *l;
213               
214                for( l = irc->channels; l; l = l->next )
215                        irc_send_names( l->data );
216        }
217        */
218}
219
220static void irc_cmd_part( irc_t *irc, char **cmd )
221{
222        irc_channel_t *ic;
223       
224        if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
225        {
226                irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
227        }
228        else if( irc_channel_del_user( ic, irc->user, IRC_CDU_PART, cmd[2] ) )
229        {
230                if( ic->f->part )
231                        ic->f->part( ic, NULL );
232        }
233        else
234        {
235                irc_send_num( irc, 442, "%s :You're not on that channel", cmd[1] );
236        }
237}
238
239static void irc_cmd_whois( irc_t *irc, char **cmd )
240{
241        char *nick = cmd[1];
242        irc_user_t *iu = irc_user_by_name( irc, nick );
243       
244        if( iu )
245                irc_send_whois( iu );
246        else
247                irc_send_num( irc, 401, "%s :Nick does not exist", nick );
248}
249
250static void irc_cmd_whowas( irc_t *irc, char **cmd )
251{
252        /* For some reason irssi tries a whowas when whois fails. We can
253           ignore this, but then the user never gets a "user not found"
254           message from irssi which is a bit annoying. So just respond
255           with not-found and irssi users will get better error messages */
256       
257        irc_send_num( irc, 406, "%s :Nick does not exist", cmd[1] );
258        irc_send_num( irc, 369, "%s :End of WHOWAS", cmd[1] );
259}
260
261static void irc_cmd_motd( irc_t *irc, char **cmd )
262{
263        irc_send_motd( irc );
264}
265
266static void irc_cmd_mode( irc_t *irc, char **cmd )
267{
268        if( irc_channel_name_ok( cmd[1] ) )
269        {
270                irc_channel_t *ic;
271               
272                if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
273                        irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
274                else if( cmd[2] )
275                {
276                        if( *cmd[2] == '+' || *cmd[2] == '-' )
277                                irc_send_num( irc, 477, "%s :Can't change channel modes", cmd[1] );
278                        else if( *cmd[2] == 'b' )
279                                irc_send_num( irc, 368, "%s :No bans possible", cmd[1] );
280                }
281                else
282                        irc_send_num( irc, 324, "%s +%s", cmd[1], ic->mode );
283        }
284        else
285        {
286                if( nick_cmp( cmd[1], irc->user->nick ) == 0 )
287                {
288                        if( cmd[2] )
289                                irc_umode_set( irc, cmd[2], 0 );
290                        else
291                                irc_send_num( irc, 221, "+%s", irc->umode );
292                }
293                else
294                        irc_send_num( irc, 502, ":Don't touch their modes" );
295        }
296}
297
298static void irc_cmd_who( irc_t *irc, char **cmd )
299{
300        char *channel = cmd[1];
301        irc_channel_t *ic;
302       
303        if( !channel || *channel == '0' || *channel == '*' || !*channel )
304                irc_send_who( irc, irc->users, "**" );
305        else if( ( ic = irc_channel_by_name( irc, channel ) ) )
306                irc_send_who( irc, ic->users, channel );
307        else
308                irc_send_num( irc, 403, "%s :No such channel", channel );
309}
310
311static void irc_cmd_privmsg( irc_t *irc, char **cmd )
312{
313        irc_channel_t *ic;
314        irc_user_t *iu;
315       
316        if( !cmd[2] ) 
317        {
318                irc_send_num( irc, 412, ":No text to send" );
319                return;
320        }
321       
322        /* Don't treat CTCP actions as real CTCPs, just convert them right now. */
323        if( g_strncasecmp( cmd[2], "\001ACTION", 7 ) == 0 )
324        {
325                cmd[2] += 4;
326                memcpy( cmd[2], "/me", 3 );
327                if( cmd[2][strlen(cmd[2])-1] == '\001' )
328                        cmd[2][strlen(cmd[2])-1] = '\0';
329        }
330       
331        if( irc_channel_name_ok( cmd[1] ) &&
332            ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
333        {
334                if( cmd[2][0] == '\001' )
335                {
336                        /* CTCPs to channels? Nah. Maybe later. */
337                }
338                else if( ic->f->privmsg )
339                        ic->f->privmsg( ic, cmd[2] );
340        }
341        else if( ( iu = irc_user_by_name( irc, cmd[1] ) ) )
342        {
343                if( cmd[2][0] == '\001' )
344                {
345                        char **ctcp;
346                       
347                        if( iu->f->ctcp == NULL )
348                                return;
349                        if( cmd[2][strlen(cmd[2])-1] == '\001' )
350                                cmd[2][strlen(cmd[2])-1] = '\0';
351                       
352                        ctcp = split_command_parts( cmd[2] + 1 );
353                        iu->f->ctcp( iu, ctcp );
354                }
355                else if( iu->f->privmsg )
356                {
357                        iu->last_channel = NULL;
358                        iu->f->privmsg( iu, cmd[2] );
359                }
360        }
361        else
362        {
363                irc_send_num( irc, 401, "%s :No such nick/channel", cmd[1] );
364        }
365}
366
367static void irc_cmd_notice( irc_t *irc, char **cmd )
368{
369        if( !cmd[2] ) 
370        {
371                irc_send_num( irc, 412, ":No text to send" );
372                return;
373        }
374       
375        /* At least for now just echo. IIRC some IRC clients use self-notices
376           for lag checks, so try to support that. */
377        if( nick_cmp( cmd[1], irc->user->nick ) == 0 )
378                irc_send_msg( irc->user, "NOTICE", irc->user->nick, cmd[2], NULL );
379}
380
381static void irc_cmd_nickserv( irc_t *irc, char **cmd )
382{
383        /* [SH] This aliases the NickServ command to PRIVMSG root */
384        /* [TV] This aliases the NS command to PRIVMSG root as well */
385        root_command( irc, cmd + 1 );
386}
387
388
389
390static void irc_cmd_oper( irc_t *irc, char **cmd )
391{
392        if( global.conf->oper_pass &&
393            ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ?
394                md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 :
395                strcmp( cmd[2], global.conf->oper_pass ) == 0 ) )
396        {
397                irc_umode_set( irc, "+o", 1 );
398                irc_send_num( irc, 381, ":Password accepted" );
399        }
400        else
401        {
402                irc_send_num( irc, 432, ":Incorrect password" );
403        }
404}
405
406static void irc_cmd_invite( irc_t *irc, char **cmd )
407{
408        irc_channel_t *ic;
409        irc_user_t *iu;
410       
411        if( ( iu = irc_user_by_name( irc, cmd[1] ) ) == NULL )
412        {
413                irc_send_num( irc, 401, "%s :No such nick", cmd[1] );
414                return;
415        }
416        else if( ( ic = irc_channel_by_name( irc, cmd[2] ) ) == NULL )
417        {
418                irc_send_num( irc, 403, "%s :No such channel", cmd[2] );
419                return;
420        }
421       
422        if( !ic->f->invite )
423                irc_send_num( irc, 482, "%s :Can't invite people here", cmd[2] );
424        else if( ic->f->invite( ic, iu ) )
425                irc_send_num( irc, 341, "%s %s", iu->nick, ic->name );
426}
427
428static void irc_cmd_userhost( irc_t *irc, char **cmd )
429{
430        int i;
431       
432        /* [TV] Usable USERHOST-implementation according to
433                RFC1459. Without this, mIRC shows an error
434                while connecting, and the used way of rejecting
435                breaks standards.
436        */
437       
438        for( i = 1; cmd[i]; i ++ )
439        {
440                irc_user_t *iu = irc_user_by_name( irc, cmd[i] );
441               
442                if( iu )
443                        irc_send_num( irc, 302, ":%s=%c%s@%s", iu->nick,
444                                      irc_user_get_away( iu ) ? '-' : '+',
445                                      iu->user, iu->host );
446        }
447}
448
449static void irc_cmd_ison( irc_t *irc, char **cmd )
450{
451        char buff[IRC_MAX_LINE];
452        int lenleft, i;
453       
454        buff[0] = '\0';
455       
456        /* [SH] Leave room for : and \0 */
457        lenleft = IRC_MAX_LINE - 2;
458       
459        for( i = 1; cmd[i]; i ++ )
460        {
461                char *this, *next;
462               
463                this = cmd[i];
464                while( *this )
465                {
466                        irc_user_t *iu;
467                       
468                        if( ( next = strchr( this, ' ' ) ) )
469                                *next = 0;
470                       
471                        if( ( iu = irc_user_by_name( irc, this ) ) &&
472                            iu->bu && iu->bu->flags & BEE_USER_ONLINE )
473                        {
474                                lenleft -= strlen( iu->nick ) + 1;
475                               
476                                if( lenleft < 0 )
477                                        break;
478                               
479                                strcat( buff, iu->nick );
480                                strcat( buff, " " );
481                        }
482                       
483                        if( next )
484                        {
485                                *next = ' ';
486                                this = next + 1;
487                        }
488                        else
489                        {
490                                break;
491                        }   
492                }
493               
494                /* *sigh* */
495                if( lenleft < 0 )
496                        break;
497        }
498       
499        if( strlen( buff ) > 0 )
500                buff[strlen(buff)-1] = '\0';
501       
502        irc_send_num( irc, 303, ":%s", buff );
503}
504
505static void irc_cmd_watch( irc_t *irc, char **cmd )
506{
507        int i;
508       
509        /* Obviously we could also mark a user structure as being
510           watched, but what if the WATCH command is sent right
511           after connecting? The user won't exist yet then... */
512        for( i = 1; cmd[i]; i ++ )
513        {
514                char *nick;
515                irc_user_t *iu;
516               
517                if( !cmd[i][0] || !cmd[i][1] )
518                        break;
519               
520                nick = g_strdup( cmd[i] + 1 );
521                nick_lc( nick );
522               
523                iu = irc_user_by_name( irc, nick );
524               
525                if( cmd[i][0] == '+' )
526                {
527                        if( !g_hash_table_lookup( irc->watches, nick ) )
528                                g_hash_table_insert( irc->watches, nick, nick );
529                       
530                        if( iu && iu->bu && iu->bu->flags & BEE_USER_ONLINE )
531                                irc_send_num( irc, 604, "%s %s %s %d :%s", iu->nick, iu->user,
532                                              iu->host, (int) time( NULL ), "is online" );
533                        else
534                                irc_send_num( irc, 605, "%s %s %s %d :%s", nick, "*", "*",
535                                              (int) time( NULL ), "is offline" );
536                }
537                else if( cmd[i][0] == '-' )
538                {
539                        gpointer okey, ovalue;
540                       
541                        if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) )
542                        {
543                                g_hash_table_remove( irc->watches, okey );
544                                g_free( okey );
545                               
546                                irc_send_num( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
547                        }
548                }
549        }
550}
551
552static void irc_cmd_topic( irc_t *irc, char **cmd )
553{
554        irc_channel_t *ic = irc_channel_by_name( irc, cmd[1] );
555        const char *new = cmd[2];
556       
557        if( ic == NULL )
558        {
559                irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
560        }
561        else if( new )
562        {
563                if( ic->f->topic == NULL )
564                        irc_send_num( irc, 482, "%s :Can't change this channel's topic", ic->name );
565                else if( ic->f->topic( ic, new ) )
566                        irc_send_topic( ic, TRUE );
567        }
568        else
569        {
570                irc_send_topic( ic, FALSE );
571        }
572}
573
574static void irc_cmd_away( irc_t *irc, char **cmd )
575{
576        if( cmd[1] && *cmd[1] )
577        {
578                char away[strlen(cmd[1])+1];
579                int i, j;
580               
581                /* Copy away string, but skip control chars. Mainly because
582                   Jabber really doesn't like them. */
583                for( i = j = 0; cmd[1][i]; i ++ )
584                        if( ( away[j] = cmd[1][i] ) >= ' ' )
585                                j ++;
586                away[j] = '\0';
587               
588                irc_send_num( irc, 306, ":You're now away: %s", away );
589                set_setstr( &irc->b->set, "away", away );
590        }
591        else
592        {
593                irc_send_num( irc, 305, ":Welcome back" );
594                set_setstr( &irc->b->set, "away", NULL );
595        }
596}
597
598static void irc_cmd_version( irc_t *irc, char **cmd )
599{
600        irc_send_num( irc, 351, "bitlbee-%s. %s :%s/%s ",
601                      BITLBEE_VERSION, irc->root->host, ARCH, CPU );
602}
603
604static void irc_cmd_completions( irc_t *irc, char **cmd )
605{
606        help_t *h;
607        set_t *s;
608        int i;
609       
610        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS OK" );
611       
612        for( i = 0; commands[i].command; i ++ )
613                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS %s", commands[i].command );
614       
615        for( h = global.help; h; h = h->next )
616                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS help %s", h->title );
617       
618        for( s = irc->b->set; s; s = s->next )
619                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS set %s", s->key );
620       
621        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS END" );
622}
623
624static void irc_cmd_rehash( irc_t *irc, char **cmd )
625{
626        if( global.conf->runmode == RUNMODE_INETD )
627                ipc_master_cmd_rehash( NULL, NULL );
628        else
629                ipc_to_master( cmd );
630       
631        irc_send_num( irc, 382, "%s :Rehashing", global.conf_file );
632}
633
634static const command_t irc_commands[] = {
635        { "pass",        1, irc_cmd_pass,        0 },
636        { "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
637        { "nick",        1, irc_cmd_nick,        0 },
638        { "quit",        0, irc_cmd_quit,        0 },
639        { "ping",        0, irc_cmd_ping,        0 },
640        { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
641        { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
642        { "names",       1, irc_cmd_names,       IRC_CMD_LOGGED_IN },
643        { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
644        { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
645        { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
646        { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
647        { "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
648        { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
649        { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
650        { "notice",      1, irc_cmd_notice,      IRC_CMD_LOGGED_IN },
651        { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
652        { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
653        { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
654        { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
655        { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
656        { "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
657        { "ison",        1, irc_cmd_ison,        IRC_CMD_LOGGED_IN },
658        { "watch",       1, irc_cmd_watch,       IRC_CMD_LOGGED_IN },
659        { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
660        { "topic",       1, irc_cmd_topic,       IRC_CMD_LOGGED_IN },
661        { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
662        { "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
663        { "deaf",        0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
664        { "wallops",     1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
665        { "wall",        1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
666        { "rehash",      0, irc_cmd_rehash,      IRC_CMD_OPER_ONLY },
667        { "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
668        { "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
669        { NULL }
670};
671
672void irc_exec( irc_t *irc, char *cmd[] )
673{       
674        int i, n_arg;
675       
676        if( !cmd[0] )
677                return;
678       
679        for( i = 0; irc_commands[i].command; i++ )
680                if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 )
681                {
682                        /* There should be no typo in the next line: */
683                        for( n_arg = 0; cmd[n_arg]; n_arg ++ ); n_arg --;
684                       
685                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
686                        {
687                                irc_send_num( irc, 462, ":Only allowed before logging in" );
688                        }
689                        else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
690                        {
691                                irc_send_num( irc, 451, ":Register first" );
692                        }
693                        else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
694                        {
695                                irc_send_num( irc, 481, ":Permission denied - You're not an IRC operator" );
696                        }
697                        else if( n_arg < irc_commands[i].required_parameters )
698                        {
699                                irc_send_num( irc, 461, "%s :Need more parameters", cmd[0] );
700                        }
701                        else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
702                        {
703                                /* IPC doesn't make sense in inetd mode,
704                                    but the function will catch that. */
705                                ipc_to_master( cmd );
706                        }
707                        else
708                        {
709                                irc_commands[i].execute( irc, cmd );
710                        }
711                       
712                        return;
713                }
714       
715        if( irc->status >= USTATUS_LOGGED_IN )
716                irc_send_num( irc, 421, "%s :Unknown command", cmd[0] );
717}
Note: See TracBrowser for help on using the repository browser.