source: irc_commands.c @ f9dbc99

Last change on this file since f9dbc99 was f9756bd, checked in by Wilmer van der Gaast <wilmer@…>, at 2008-03-30T21:26:16Z

Changed charset handling: irc_t keeps two iconv structures, which are just
used for every line sent and received, so now there's no need to use
g_iconv_open() every time a message comes in/out. Also, fixed a small
memory leak that was there for a long time but somehow never caught my
attention.

  • Property mode set to 100644
File size: 18.4 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{
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 );
[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        {
195                if( ( cmd[1][0] == '#' || cmd[1][0] == '&' ) && cmd[1][1] )
196                {
197                        user_t *u = user_find( irc, cmd[1] + 1 );
198                       
[0da65d5]199                        if( u && u->ic && u->ic->acc->prpl->chat_with )
[0298d11]200                        {
201                                irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] );
202                               
[0da65d5]203                                if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) )
[0298d11]204                                {
[c38e965]205                                        irc_usermsg( irc, "Could not open a groupchat with %s.", u->nick );
[0298d11]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
[f73b969]224static void irc_cmd_invite( irc_t *irc, char **cmd )
[0298d11]225{
226        char *nick = cmd[1], *channel = cmd[2];
[0e7ab64]227        struct groupchat *c = irc_chat_by_channel( irc, channel );
[0298d11]228        user_t *u = user_find( irc, nick );
229       
[0da65d5]230        if( u && c && ( u->ic == c->ic ) )
231                if( c->ic && c->ic->acc->prpl->chat_invite )
[0298d11]232                {
[c058ff9]233                        c->ic->acc->prpl->chat_invite( c, u->handle, NULL );
[0298d11]234                        irc_reply( irc, 341, "%s %s", nick, channel );
[f73b969]235                        return;
[0298d11]236                }
237       
238        irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
239}
240
[f73b969]241static void irc_cmd_privmsg( irc_t *irc, char **cmd )
[0298d11]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;
[5c9512f]256                        char *t = set_getstr( &irc->set, "default_target" );
[0298d11]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                        {
[f9756bd]280                                g_free( irc->last_target );
[0298d11]281                                irc->last_target = g_strdup( cmd[1] );
282                        }
283                }
284                else
285                {
286                        irc->is_private = 1;
287                }
[6bbb939]288                irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? OPT_AWAY : 0 );
[0298d11]289        }
290}
291
[f73b969]292static void irc_cmd_who( irc_t *irc, char **cmd )
[0298d11]293{
294        char *channel = cmd[1];
295        user_t *u = irc->users;
[0da65d5]296        struct groupchat *c;
[0298d11]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                }
[0e7ab64]312        else if( ( c = irc_chat_by_channel( irc, channel ) ) )
[0298d11]313                for( l = c->in_room; l; l = l->next )
314                {
[0da65d5]315                        if( ( u = user_findhandle( c->ic, l->data ) ) )
[0298d11]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       
[b23c5c7]321        irc_reply( irc, 315, "%s :End of /WHO list", channel?channel:"**" );
[0298d11]322}
323
[f73b969]324static void irc_cmd_userhost( irc_t *irc, char **cmd )
[0298d11]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
[f73b969]345static void irc_cmd_ison( irc_t *irc, char **cmd )
[0298d11]346{
347        user_t *u;
[b4e4b95]348        char buff[IRC_MAX_LINE];
[0298d11]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        {
[42616d1]358                char *this, *next;
359               
360                this = cmd[i];
361                while( *this )
[0298d11]362                {
[42616d1]363                        if( ( next = strchr( this, ' ' ) ) )
364                                *next = 0;
[0298d11]365                       
[42616d1]366                        if( ( u = user_find( irc, this ) ) && u->online )
[0298d11]367                        {
[42616d1]368                                lenleft -= strlen( u->nick ) + 1;
369                               
370                                if( lenleft < 0 )
371                                        break;
372                               
373                                strcat( buff, u->nick );
374                                strcat( buff, " " );
[0298d11]375                        }
376                       
[42616d1]377                        if( next )
378                        {
379                                *next = ' ';
380                                this = next + 1;
381                        }
382                        else
383                        {
384                                break;
385                        }   
[0298d11]386                }
[42616d1]387               
388                /* *sigh* */
389                if( lenleft < 0 )
390                        break;
[0298d11]391        }
392       
393        if( strlen( buff ) > 0 )
394                buff[strlen(buff)-1] = '\0';
395       
396        irc_reply( irc, 303, ":%s", buff );
397}
398
[f73b969]399static void irc_cmd_watch( irc_t *irc, char **cmd )
[0298d11]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 )
[fc630f9]425                                irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "is online" );
[0298d11]426                        else
[fc630f9]427                                irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", (int) time( NULL ), "is offline" );
[0298d11]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
[f73b969]444static void irc_cmd_topic( irc_t *irc, char **cmd )
[0298d11]445{
[50e1776]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        }
[0298d11]456        else
[50e1776]457        {
458                /* Get the topic */
459                irc_topic( irc, channel );
460        }
[0298d11]461}
462
[f73b969]463static void irc_cmd_away( irc_t *irc, char **cmd )
[0298d11]464{
465        user_t *u = user_find( irc, irc->nick );
466        char *away = cmd[1];
[a91ecee]467        account_t *a;
[0298d11]468       
[f73b969]469        if( !u ) return;
[0298d11]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       
[a91ecee]494        for( a = irc->accounts; a; a = a->next )
[0298d11]495        {
[0da65d5]496                struct im_connection *ic = a->ic;
[0298d11]497               
[0da65d5]498                if( ic && ic->flags & OPT_LOGGED_IN )
[84b045d]499                        imc_set_away( ic, u->away );
[0298d11]500        }
501}
502
[f73b969]503static void irc_cmd_whois( irc_t *irc, char **cmd )
[0298d11]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               
[0da65d5]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 );
[0298d11]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
[f73b969]532static void irc_cmd_whowas( irc_t *irc, char **cmd )
[0298d11]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
[f73b969]543static void irc_cmd_nickserv( irc_t *irc, char **cmd )
[0298d11]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
[f73b969]550static void irc_cmd_motd( irc_t *irc, char **cmd )
[0298d11]551{
552        irc_motd( irc );
553}
554
[f73b969]555static void irc_cmd_pong( irc_t *irc, char **cmd )
[0298d11]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
[82898af]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
[f73b969]568static void irc_cmd_completions( irc_t *irc, char **cmd )
[0298d11]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 )
[0fbda193]581                irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->title );
[0298d11]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
[f73b969]589static void irc_cmd_rehash( irc_t *irc, char **cmd )
[f4a5940]590{
[5424c76]591        if( global.conf->runmode == RUNMODE_INETD )
592                ipc_master_cmd_rehash( NULL, NULL );
593        else
594                ipc_to_master( cmd );
[f4a5940]595       
[eeb85a8]596        irc_reply( irc, 382, "%s :Rehashing", global.conf_file );
[f4a5940]597}
598
[0298d11]599static const command_t irc_commands[] = {
[a199d33]600        { "pass",        1, irc_cmd_pass,        0 },
[0298d11]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 },
[82898af]625        { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
[0298d11]626        { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
[0431ea1]627        { "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[48721c3]628        { "wallops",     1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[dfc8a46]629        { "wall",        1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[f4a5940]630        { "rehash",      0, irc_cmd_rehash,      IRC_CMD_OPER_ONLY },
[54879ab]631        { "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[48721c3]632        { "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
[0298d11]633        { NULL }
634};
635
[f73b969]636void irc_exec( irc_t *irc, char *cmd[] )
[0298d11]637{       
[f1d38f2]638        int i, n_arg;
[0298d11]639       
640        if( !cmd[0] )
[f73b969]641                return;
[0298d11]642       
643        for( i = 0; irc_commands[i].command; i++ )
644                if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 )
645                {
[f1d38f2]646                        /* There should be no typo in the next line: */
647                        for( n_arg = 0; cmd[n_arg]; n_arg ++ ); n_arg --;
648                       
[79e826a]649                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
[edf9657]650                        {
651                                irc_reply( irc, 462, ":Only allowed before logging in" );
652                        }
[3af70b0]653                        else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
[edf9657]654                        {
655                                irc_reply( irc, 451, ":Register first" );
656                        }
[f73b969]657                        else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
[edf9657]658                        {
659                                irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" );
660                        }
[f1d38f2]661                        else if( n_arg < irc_commands[i].required_parameters )
[f73b969]662                        {
663                                irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
664                        }
665                        else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
666                        {
[5424c76]667                                /* IPC doesn't make sense in inetd mode,
668                                    but the function will catch that. */
[0431ea1]669                                ipc_to_master( cmd );
[f73b969]670                        }
[0431ea1]671                        else
[f73b969]672                        {
673                                irc_commands[i].execute( irc, cmd );
674                        }
675                       
[2f13222]676                        return;
[0298d11]677                }
[2f13222]678       
679        if( irc->status >= USTATUS_LOGGED_IN )
680                irc_reply( irc, 421, "%s :Unknown command", cmd[0] );
[0298d11]681}
Note: See TracBrowser for help on using the repository browser.