source: irc_commands.c @ 4164e62

Last change on this file since 4164e62 was e59b4f6, checked in by Wilmer van der Gaast <wilmer@…>, at 2009-10-04T19:00:53Z

Fixed embarassing early free() bug that sat in the WATCH command handling
for *years*. I guess it took a while for IRC clients to actually use that
functionality...

  • Property mode set to 100644
File size: 18.1 KB
RevLine 
[0298d11]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"
[0431ea1]28#include "ipc.h"
[0298d11]29
[f73b969]30static void irc_cmd_pass( irc_t *irc, char **cmd )
[0298d11]31{
[a199d33]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 &&
[c029350]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 ) )
[0298d11]48        {
[79e826a]49                irc->status |= USTATUS_AUTHORIZED;
[de3e100]50                irc_check_login( irc );
[0298d11]51        }
[a199d33]52        else if( global.conf->auth_pass )
[0298d11]53        {
[b23c5c7]54                irc_reply( irc, 464, ":Incorrect password" );
[0298d11]55        }
[a199d33]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        }
[0298d11]62}
63
[f73b969]64static void irc_cmd_user( irc_t *irc, char **cmd )
[0298d11]65{
[edf9657]66        irc->user = g_strdup( cmd[1] );
67        irc->realname = g_strdup( cmd[4] );
68       
69        irc_check_login( irc );
[0298d11]70}
71
[f73b969]72static void irc_cmd_nick( irc_t *irc, char **cmd )
[0298d11]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] );
[edf9657]91               
92                irc_check_login( irc );
[0298d11]93        }
94}
95
[f73b969]96static void irc_cmd_quit( irc_t *irc, char **cmd )
[0298d11]97{
[f73b969]98        if( cmd[1] && *cmd[1] )
99                irc_abort( irc, 0, "Quit: %s", cmd[1] );
100        else
101                irc_abort( irc, 0, "Leaving..." );
[0298d11]102}
103
[f73b969]104static void irc_cmd_ping( irc_t *irc, char **cmd )
[0298d11]105{
106        irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost );
107}
108
[f73b969]109static void irc_cmd_oper( irc_t *irc, char **cmd )
[0298d11]110{
[ec0355f]111        if( global.conf->oper_pass &&
[c029350]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 ) )
[b23c5c7]115        {
[0298d11]116                irc_umode_set( irc, "+o", 1 );
[b23c5c7]117                irc_reply( irc, 381, ":Password accepted" );
118        }
119        else
120        {
121                irc_reply( irc, 432, ":Incorrect password" );
122        }
[0298d11]123}
124
[f73b969]125static void irc_cmd_mode( irc_t *irc, char **cmd )
[0298d11]126{
[39f93f0]127        if( strchr( CTYPES, *cmd[1] ) )
[0298d11]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 );
[2f13222]145                        else
146                                irc_reply( irc, 221, "+%s", irc->umode );
[0298d11]147                }
148                else
149                        irc_reply( irc, 502, ":Don't touch their modes" );
150        }
151}
152
[f73b969]153static void irc_cmd_names( irc_t *irc, char **cmd )
[0298d11]154{
155        irc_names( irc, cmd[1]?cmd[1]:irc->channel );
156}
157
[f73b969]158static void irc_cmd_part( irc_t *irc, char **cmd )
[0298d11]159{
[0da65d5]160        struct groupchat *c;
[0298d11]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        }
[0e7ab64]170        else if( ( c = irc_chat_by_channel( irc, cmd[1] ) ) )
[0298d11]171        {
172                user_t *u = user_find( irc, irc->nick );
173               
174                irc_part( irc, u, c->channel );
175               
[0da65d5]176                if( c->ic )
[0298d11]177                {
178                        c->joined = 0;
[0da65d5]179                        c->ic->acc->prpl->chat_leave( c );
[0298d11]180                }
181        }
182        else
183        {
184                irc_reply( irc, 403, "%s :No such channel", cmd[1] );
185        }
186}
187
[f73b969]188static void irc_cmd_join( irc_t *irc, char **cmd )
[0298d11]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        {
[39f93f0]195                struct chat *c;
196               
197                if( strchr( CTYPES, cmd[1][0] ) == NULL || cmd[1][1] == 0 )
[e180c59]198                        irc_reply( irc, 479, "%s :Invalid channel name", cmd[1] );
199                else if( ( c = chat_bychannel( irc, cmd[1] ) ) && c->acc && c->acc->ic )
[94acdd0]200                        chat_join( irc, c, cmd[2] );
[0298d11]201                else
202                        irc_reply( irc, 403, "%s :No such channel", cmd[1] );
203        }
204}
205
[f73b969]206static void irc_cmd_invite( irc_t *irc, char **cmd )
[0298d11]207{
208        char *nick = cmd[1], *channel = cmd[2];
[0e7ab64]209        struct groupchat *c = irc_chat_by_channel( irc, channel );
[0298d11]210        user_t *u = user_find( irc, nick );
211       
[0da65d5]212        if( u && c && ( u->ic == c->ic ) )
213                if( c->ic && c->ic->acc->prpl->chat_invite )
[0298d11]214                {
[c058ff9]215                        c->ic->acc->prpl->chat_invite( c, u->handle, NULL );
[0298d11]216                        irc_reply( irc, 341, "%s %s", nick, channel );
[f73b969]217                        return;
[0298d11]218                }
219       
220        irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
221}
222
[f73b969]223static void irc_cmd_privmsg( irc_t *irc, char **cmd )
[0298d11]224{
225        if ( !cmd[2] ) 
226        {
227                irc_reply( irc, 412, ":No text to send" );
228        }
229        else if ( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 ) 
230        {
231                irc_write( irc, ":%s!%s@%s %s %s :%s", irc->nick, irc->user, irc->host, cmd[0], cmd[1], cmd[2] ); 
232        }
233        else 
234        {
235                if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
236                {
237                        unsigned int i;
[5c9512f]238                        char *t = set_getstr( &irc->set, "default_target" );
[0298d11]239                       
240                        if( g_strcasecmp( t, "last" ) == 0 && irc->last_target )
241                                cmd[1] = irc->last_target;
242                        else if( g_strcasecmp( t, "root" ) == 0 )
243                                cmd[1] = irc->mynick;
244                       
245                        for( i = 0; i < strlen( cmd[2] ); i ++ )
246                        {
247                                if( cmd[2][i] == ' ' ) break;
248                                if( cmd[2][i] == ':' || cmd[2][i] == ',' )
249                                {
250                                        cmd[1] = cmd[2];
251                                        cmd[2] += i;
252                                        *cmd[2] = 0;
253                                        while( *(++cmd[2]) == ' ' );
254                                        break;
255                                }
256                        }
257                       
258                        irc->is_private = 0;
259                       
260                        if( cmd[1] != irc->last_target )
261                        {
[f9756bd]262                                g_free( irc->last_target );
[0298d11]263                                irc->last_target = g_strdup( cmd[1] );
264                        }
265                }
266                else
267                {
268                        irc->is_private = 1;
269                }
[6bbb939]270                irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? OPT_AWAY : 0 );
[0298d11]271        }
272}
273
[f73b969]274static void irc_cmd_who( irc_t *irc, char **cmd )
[0298d11]275{
276        char *channel = cmd[1];
277        user_t *u = irc->users;
[0da65d5]278        struct groupchat *c;
[0298d11]279        GList *l;
280       
281        if( !channel || *channel == '0' || *channel == '*' || !*channel )
282                while( u )
283                {
284                        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 );
285                        u = u->next;
286                }
287        else if( g_strcasecmp( channel, irc->channel ) == 0 )
288                while( u )
289                {
290                        if( u->online )
291                                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 );
292                        u = u->next;
293                }
[0e7ab64]294        else if( ( c = irc_chat_by_channel( irc, channel ) ) )
[0298d11]295                for( l = c->in_room; l; l = l->next )
296                {
[0da65d5]297                        if( ( u = user_findhandle( c->ic, l->data ) ) )
[0298d11]298                                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 );
299                }
300        else if( ( u = user_find( irc, channel ) ) )
301                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 );
302       
[b23c5c7]303        irc_reply( irc, 315, "%s :End of /WHO list", channel?channel:"**" );
[0298d11]304}
305
[f73b969]306static void irc_cmd_userhost( irc_t *irc, char **cmd )
[0298d11]307{
308        user_t *u;
309        int i;
310       
311        /* [TV] Usable USERHOST-implementation according to
312                RFC1459. Without this, mIRC shows an error
313                while connecting, and the used way of rejecting
314                breaks standards.
315        */
316       
317        for( i = 1; cmd[i]; i ++ )
318                if( ( u = user_find( irc, cmd[i] ) ) )
319                {
320                        if( u->online && u->away )
321                                irc_reply( irc, 302, ":%s=-%s@%s", u->nick, u->user, u->host );
322                        else
323                                irc_reply( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host );
324                }
325}
326
[f73b969]327static void irc_cmd_ison( irc_t *irc, char **cmd )
[0298d11]328{
329        user_t *u;
[b4e4b95]330        char buff[IRC_MAX_LINE];
[0298d11]331        int lenleft, i;
332       
333        buff[0] = '\0';
334       
335        /* [SH] Leave room for : and \0 */
336        lenleft = IRC_MAX_LINE - 2;
337       
338        for( i = 1; cmd[i]; i ++ )
339        {
[42616d1]340                char *this, *next;
341               
342                this = cmd[i];
343                while( *this )
[0298d11]344                {
[42616d1]345                        if( ( next = strchr( this, ' ' ) ) )
346                                *next = 0;
[0298d11]347                       
[42616d1]348                        if( ( u = user_find( irc, this ) ) && u->online )
[0298d11]349                        {
[42616d1]350                                lenleft -= strlen( u->nick ) + 1;
351                               
352                                if( lenleft < 0 )
353                                        break;
354                               
355                                strcat( buff, u->nick );
356                                strcat( buff, " " );
[0298d11]357                        }
358                       
[42616d1]359                        if( next )
360                        {
361                                *next = ' ';
362                                this = next + 1;
363                        }
364                        else
365                        {
366                                break;
367                        }   
[0298d11]368                }
[42616d1]369               
370                /* *sigh* */
371                if( lenleft < 0 )
372                        break;
[0298d11]373        }
374       
375        if( strlen( buff ) > 0 )
376                buff[strlen(buff)-1] = '\0';
377       
378        irc_reply( irc, 303, ":%s", buff );
379}
380
[f73b969]381static void irc_cmd_watch( irc_t *irc, char **cmd )
[0298d11]382{
383        int i;
384       
385        /* Obviously we could also mark a user structure as being
386           watched, but what if the WATCH command is sent right
387           after connecting? The user won't exist yet then... */
388        for( i = 1; cmd[i]; i ++ )
389        {
390                char *nick;
391                user_t *u;
392               
393                if( !cmd[i][0] || !cmd[i][1] )
394                        break;
395               
396                nick = g_strdup( cmd[i] + 1 );
397                nick_lc( nick );
398               
399                u = user_find( irc, nick );
400               
401                if( cmd[i][0] == '+' )
402                {
403                        if( !g_hash_table_lookup( irc->watches, nick ) )
404                                g_hash_table_insert( irc->watches, nick, nick );
405                       
406                        if( u && u->online )
[fc630f9]407                                irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "is online" );
[0298d11]408                        else
[fc630f9]409                                irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", (int) time( NULL ), "is offline" );
[0298d11]410                }
411                else if( cmd[i][0] == '-' )
412                {
413                        gpointer okey, ovalue;
414                       
415                        if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) )
416                        {
417                                g_hash_table_remove( irc->watches, okey );
[e59b4f6]418                                g_free( okey );
[0298d11]419                               
420                                irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
421                        }
422                }
423        }
424}
425
[f73b969]426static void irc_cmd_topic( irc_t *irc, char **cmd )
[0298d11]427{
[50e1776]428        char *channel = cmd[1];
429        char *topic = cmd[2];
430       
431        if( topic )
432        {
433                /* Send the topic */
434                struct groupchat *c = irc_chat_by_channel( irc, channel );
435                if( c && c->ic && c->ic->acc->prpl->chat_topic )
436                        c->ic->acc->prpl->chat_topic( c, topic );
437        }
[0298d11]438        else
[50e1776]439        {
440                /* Get the topic */
441                irc_topic( irc, channel );
442        }
[0298d11]443}
444
[f73b969]445static void irc_cmd_away( irc_t *irc, char **cmd )
[0298d11]446{
447        user_t *u = user_find( irc, irc->nick );
448        char *away = cmd[1];
[a91ecee]449        account_t *a;
[0298d11]450       
[f73b969]451        if( !u ) return;
[0298d11]452       
453        if( away && *away )
454        {
455                int i, j;
456               
457                /* Copy away string, but skip control chars. Mainly because
458                   Jabber really doesn't like them. */
459                u->away = g_malloc( strlen( away ) + 1 );
460                for( i = j = 0; away[i]; i ++ )
461                        if( ( u->away[j] = away[i] ) >= ' ' )
462                                j ++;
463                u->away[j] = 0;
464               
465                irc_reply( irc, 306, ":You're now away: %s", u->away );
466                /* irc_umode_set( irc, irc->myhost, "+a" ); */
467        }
468        else
469        {
470                if( u->away ) g_free( u->away );
471                u->away = NULL;
472                /* irc_umode_set( irc, irc->myhost, "-a" ); */
473                irc_reply( irc, 305, ":Welcome back" );
474        }
475       
[a91ecee]476        for( a = irc->accounts; a; a = a->next )
[0298d11]477        {
[0da65d5]478                struct im_connection *ic = a->ic;
[0298d11]479               
[0da65d5]480                if( ic && ic->flags & OPT_LOGGED_IN )
[84b045d]481                        imc_set_away( ic, u->away );
[0298d11]482        }
483}
484
[f73b969]485static void irc_cmd_whois( irc_t *irc, char **cmd )
[0298d11]486{
487        char *nick = cmd[1];
488        user_t *u = user_find( irc, nick );
489       
490        if( u )
491        {
492                irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname );
493               
[0da65d5]494                if( u->ic )
495                        irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->ic->acc->user,
496                                   u->ic->acc->server && *u->ic->acc->server ? u->ic->acc->server : "",
497                                   u->ic->acc->prpl->name );
[0298d11]498                else
499                        irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO );
500               
501                if( !u->online )
502                        irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
503                else if( u->away )
504                        irc_reply( irc, 301, "%s :%s", u->nick, u->away );
505               
506                irc_reply( irc, 318, "%s :End of /WHOIS list", nick );
507        }
508        else
509        {
510                irc_reply( irc, 401, "%s :Nick does not exist", nick );
511        }
512}
513
[f73b969]514static void irc_cmd_whowas( irc_t *irc, char **cmd )
[0298d11]515{
516        /* For some reason irssi tries a whowas when whois fails. We can
517           ignore this, but then the user never gets a "user not found"
518           message from irssi which is a bit annoying. So just respond
519           with not-found and irssi users will get better error messages */
520       
521        irc_reply( irc, 406, "%s :Nick does not exist", cmd[1] );
522        irc_reply( irc, 369, "%s :End of WHOWAS", cmd[1] );
523}
524
[f73b969]525static void irc_cmd_nickserv( irc_t *irc, char **cmd )
[0298d11]526{
527        /* [SH] This aliases the NickServ command to PRIVMSG root */
528        /* [TV] This aliases the NS command to PRIVMSG root as well */
529        root_command( irc, cmd + 1 );
530}
531
[f73b969]532static void irc_cmd_motd( irc_t *irc, char **cmd )
[0298d11]533{
534        irc_motd( irc );
535}
536
[f73b969]537static void irc_cmd_pong( irc_t *irc, char **cmd )
[0298d11]538{
539        /* We could check the value we get back from the user, but in
540           fact we don't care, we're just happy he's still alive. */
541        irc->last_pong = gettime();
542        irc->pinging = 0;
543}
544
[82898af]545static void irc_cmd_version( irc_t *irc, char **cmd )
546{
547        irc_reply( irc, 351, "bitlbee-%s. %s :%s/%s ", BITLBEE_VERSION, irc->myhost, ARCH, CPU );
548}
549
[f73b969]550static void irc_cmd_completions( irc_t *irc, char **cmd )
[0298d11]551{
552        user_t *u = user_find( irc, irc->mynick );
553        help_t *h;
554        set_t *s;
555        int i;
556       
557        irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" );
558       
559        for( i = 0; commands[i].command; i ++ )
560                irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command );
561       
562        for( h = global.help; h; h = h->next )
[0fbda193]563                irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->title );
[0298d11]564       
565        for( s = irc->set; s; s = s->next )
566                irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS set ", s->key );
567       
568        irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "END" );
569}
570
[f73b969]571static void irc_cmd_rehash( irc_t *irc, char **cmd )
[f4a5940]572{
[5424c76]573        if( global.conf->runmode == RUNMODE_INETD )
574                ipc_master_cmd_rehash( NULL, NULL );
575        else
576                ipc_to_master( cmd );
[f4a5940]577       
[eeb85a8]578        irc_reply( irc, 382, "%s :Rehashing", global.conf_file );
[f4a5940]579}
580
[0298d11]581static const command_t irc_commands[] = {
[a199d33]582        { "pass",        1, irc_cmd_pass,        0 },
[0298d11]583        { "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
584        { "nick",        1, irc_cmd_nick,        0 },
585        { "quit",        0, irc_cmd_quit,        0 },
586        { "ping",        0, irc_cmd_ping,        0 },
587        { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
588        { "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
589        { "names",       0, irc_cmd_names,       IRC_CMD_LOGGED_IN },
590        { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
591        { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
592        { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
593        { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
594        { "notice",      1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
595        { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
596        { "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
597        { "ison",        1, irc_cmd_ison,        IRC_CMD_LOGGED_IN },
598        { "watch",       1, irc_cmd_watch,       IRC_CMD_LOGGED_IN },
599        { "topic",       1, irc_cmd_topic,       IRC_CMD_LOGGED_IN },
600        { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
601        { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
602        { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
603        { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
604        { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
605        { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
606        { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
[82898af]607        { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
[0298d11]608        { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
[0431ea1]609        { "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[565a1ea]610        { "deaf",        0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[48721c3]611        { "wallops",     1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[dfc8a46]612        { "wall",        1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[f4a5940]613        { "rehash",      0, irc_cmd_rehash,      IRC_CMD_OPER_ONLY },
[54879ab]614        { "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[48721c3]615        { "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[0298d11]616        { NULL }
617};
618
[f73b969]619void irc_exec( irc_t *irc, char *cmd[] )
[0298d11]620{       
[f1d38f2]621        int i, n_arg;
[0298d11]622       
623        if( !cmd[0] )
[f73b969]624                return;
[0298d11]625       
626        for( i = 0; irc_commands[i].command; i++ )
627                if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 )
628                {
[f1d38f2]629                        /* There should be no typo in the next line: */
630                        for( n_arg = 0; cmd[n_arg]; n_arg ++ ); n_arg --;
631                       
[79e826a]632                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
[edf9657]633                        {
634                                irc_reply( irc, 462, ":Only allowed before logging in" );
635                        }
[3af70b0]636                        else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
[edf9657]637                        {
638                                irc_reply( irc, 451, ":Register first" );
639                        }
[f73b969]640                        else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
[edf9657]641                        {
642                                irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" );
643                        }
[f1d38f2]644                        else if( n_arg < irc_commands[i].required_parameters )
[f73b969]645                        {
646                                irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
647                        }
648                        else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
649                        {
[5424c76]650                                /* IPC doesn't make sense in inetd mode,
651                                    but the function will catch that. */
[0431ea1]652                                ipc_to_master( cmd );
[f73b969]653                        }
[0431ea1]654                        else
[f73b969]655                        {
656                                irc_commands[i].execute( irc, cmd );
657                        }
658                       
[2f13222]659                        return;
[0298d11]660                }
[2f13222]661       
662        if( irc->status >= USTATUS_LOGGED_IN )
663                irc_reply( irc, 421, "%s :Unknown command", cmd[0] );
[0298d11]664}
Note: See TracBrowser for help on using the repository browser.