root/src/map/irc.c @ 25

Revision 1, 13.1 kB (checked in by jinshiro, 17 years ago)
Line 
1// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
2// For more information, see LICENCE in the main folder
3
4#include "../common/core.h"
5#include "../common/socket.h"
6#include "../common/malloc.h"
7#include "../common/db.h"
8#include "../common/timer.h"
9#include "../common/strlib.h"
10#include "../common/mmo.h"
11#include "../common/showmsg.h"
12#include "../common/version.h"
13#include "../common/nullpo.h"
14
15#include "map.h"
16#include "mob.h"
17#include "pc.h"
18#include "intif.h" //For GM Broadcast
19#include "irc.h"
20
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24
25// configuration
26short use_irc=0;
27short irc_autojoin=0;
28
29short irc_announce_flag=1;
30short irc_announce_mvp_flag=1;
31short irc_announce_jobchange_flag=1;
32short irc_announce_shop_flag=1;
33
34char irc_nick[30]="";
35char irc_password[32]="";
36char irc_channel[32]="";
37char irc_channel_pass[32]="";
38char irc_trade_channel[32]="";
39
40char irc_ip_str[128]="";
41unsigned long irc_ip=0;
42unsigned short irc_port = 6667;
43
44// variables
45int irc_fd=0;
46IRC_SI *irc_si=NULL;
47struct channel_data cd;
48int last_cd_user=0;
49
50int irc_connect_timer(int tid, unsigned int tick, int id, intptr data)
51{
52        if(irc_si && session[irc_si->fd])
53                return 0;
54        //Ok, this ShowInfo and printf are a little ugly, but they are meant to
55        //debug just how long the code freezes here. [Skotlex]
56        ShowInfo("(IRC) Connecting to %s... ", irc_ip_str);
57        irc_fd = make_connection(irc_ip,irc_port);
58        if(irc_fd > 0){
59                ShowMessage("ok\n");
60                session[irc_fd]->func_parse = irc_parse;
61        } else
62                ShowMessage("failed\n");
63        return 0;
64}
65
66void irc_announce(const char* buf)
67{
68        char send_string[256];
69
70        sprintf(send_string,"PRIVMSG %s :",irc_channel);
71        strcat(send_string, buf);
72        irc_send(send_string);
73}
74
75void irc_announce_jobchange(struct map_session_data *sd)
76{
77        char send_string[256];
78       
79        nullpo_retv(sd);
80
81        sprintf(send_string,"PRIVMSG %s :%s has changed into a %s.",irc_channel,sd->status.name,job_name(sd->status.class_));
82        irc_send(send_string);
83}
84
85void irc_announce_shop(struct map_session_data *sd, int flag)
86{
87        char send_string[256];
88        char mapname[16];
89        int maplen = 0;
90        nullpo_retv(sd);
91
92        if(flag){
93                strcpy(mapname, map[sd->bl.m].name);
94                maplen = strcspn(mapname,".");
95                mapname[maplen] = '\0';
96                mapname[0]=TOUPPER(mapname[0]);
97
98                sprintf(send_string,"PRIVMSG %s :%s has opened a shop, %s, at <%d,%d> in %s.",irc_trade_channel,sd->status.name,sd->message,sd->bl.x,sd->bl.y,mapname);
99        } else
100                sprintf(send_string,"PRIVMSG %s :%s has closed their shop.",irc_trade_channel,sd->status.name);
101
102        irc_send(send_string);
103}
104
105void irc_announce_mvp(struct map_session_data *sd, struct mob_data *md)
106{
107        char send_string[256];
108        char mapname[16];
109        int maplen = 0;
110
111        nullpo_retv(sd);
112        nullpo_retv(md);
113
114        strcpy(mapname, map[md->bl.m].name);
115        maplen = strcspn(mapname,".");
116        mapname[maplen] = '\0';
117        mapname[0]=TOUPPER(mapname[0]);
118
119        sprintf(send_string,"PRIVMSG %s :%s the %s has MVP'd %s in %s.",irc_channel,sd->status.name,job_name(sd->status.class_),md->name, mapname);
120        irc_send(send_string);
121}
122
123int irc_parse(int fd)
124{
125        if (session[fd]->flag.eof)
126        {
127                do_close(fd);
128                irc_si = NULL;
129                add_timer(gettick() + 15000, irc_connect_timer, 0, 0);
130        return 0;
131        }
132
133        if (session[fd]->session_data == NULL) {
134                irc_si = (struct IRC_Session_Info*)aMalloc(sizeof(struct IRC_Session_Info));
135                irc_si->fd = fd;
136                irc_si->state = 0;
137                session[fd]->session_data = irc_si;
138        } else if (!irc_si) {
139                irc_si = (struct IRC_Session_Info*)session[fd]->session_data;
140                irc_si->fd = fd;
141        }
142
143        if(RFIFOREST(fd) > 0)
144        {
145                send_to_parser(fd, (char*)RFIFOP(fd,0), "\n");
146                RFIFOSKIP(fd,RFIFOREST(fd));
147        }
148        return 0;
149}
150
151int irc_keepalive_timer(int tid, unsigned int tick, int id, intptr data)
152{
153        char send_string[128];
154        sprintf(send_string,"PRIVMSG %s : ", irc_nick);
155        irc_send(send_string);
156        add_timer(gettick() + 30000, irc_keepalive_timer, 0, 0);
157        return 0;
158}
159
160void irc_send(char *buf)
161{
162        int len;
163        int fd;
164       
165        if(!irc_si || !(fd = irc_si->fd) || !session[fd])
166                return;
167
168        len = strlen(buf) + 1;
169        WFIFOHEAD(fd, len);
170        sprintf((char*)WFIFOP(fd,0), "%s\n", buf);
171        WFIFOSET(fd, len);
172}
173
174void irc_parse_sub(int fd, char *incoming_string)
175{
176        char source[256];
177        char command[256];
178        char target[256];
179        char message[8192];
180        char send_string[8192];
181        char *source_nick=NULL;
182        char *source_ident=NULL;
183        char *source_host=NULL;
184        char *state_mgr=NULL;
185       
186        memset(source,'\0',256);
187        memset(command,'\0',256);
188        memset(target,'\0',256);
189        memset(message,'\0',8192);
190        memset(send_string,'\0',8192);
191
192        sscanf(incoming_string, ":%255s %255s %255s :%4095[^\r\n]", source, command, target, message);
193        if (source != NULL)
194        {
195                if (strstr(source,"!") != NULL)
196                {
197                        source_nick = strtok_r(source,"!",&state_mgr);
198                        source_ident = strtok_r(NULL,"@",&state_mgr);
199                        source_host = strtok_r(NULL,"%%",&state_mgr);
200                }
201        }
202
203        switch (irc_si->state)
204        {
205        case 0:
206                sprintf(send_string, "NICK %s", irc_nick);
207                irc_send(send_string);
208                sprintf(send_string, "USER eABot 8 * : eABot");
209                irc_send(send_string);
210                irc_si->state = 1;
211        break;
212
213        case 1:
214                if(!strcmp(command,"001"))
215                {
216                        ShowStatus("IRC: Connected to IRC.\n");
217                        sprintf(send_string, "PRIVMSG nickserv :identify %s", irc_password);
218                        irc_send(send_string);
219                        sprintf(send_string, "JOIN %s %s", irc_channel, irc_channel_pass);
220                        irc_send(send_string);
221                        sprintf(send_string,"NAMES %s",irc_channel);
222                        irc_send(send_string);
223                        irc_si->state = 2;
224                }
225                else
226                if(!strcmp(command,"433"))
227                {
228                        ShowError("IRC: Nickname %s is already taken, IRC Client unable to connect.\n", irc_nick);
229                        sprintf(send_string, "QUIT");
230                        irc_send(send_string);
231                        if(session[fd])
232                                set_eof(fd);
233                }
234        break;
235
236        case 2:
237                if(!strcmp(source, "PING"))
238                {
239                        sprintf(send_string, "PONG %s", command);
240                        irc_send(send_string);
241                }
242                else // channel message
243                if( strcmpi(target,irc_channel)==0 || strcmpi(target,irc_channel+1)==0 || strcmpi(target+1,irc_channel)==0 )
244                {       //TODO: why not allow talking to the bot directly? (|| strcmpi(irc_nick,target) == 0)
245
246                        // issue a command (usage: say @command <params> into the channel)
247                        char cmdname[256];
248                        char cmdargs[256] = "";
249                        if((strcmpi(command,"privmsg")==0)&&(sscanf(message,"@%255s %255[^\r\n]",cmdname,cmdargs)>0)&&(target[0]=='#'))
250                        {
251                                if(strcmpi(cmdname,"kami")==0)
252                                {
253                                        if(get_access(source_nick) < ACCESS_OP)
254                                                sprintf(send_string,"NOTICE %s :Access Denied",source_nick);
255                                        else
256                                        {
257                                                sprintf(send_string,"%s: %s",source_nick,cmdargs);
258                                                intif_GMmessage(send_string,strlen(send_string)+1,0);
259                                                sprintf(send_string,"NOTICE %s :Message Sent",source_nick);
260                                        }
261                                        irc_send(send_string);
262                                }
263                                else // Number of users online
264                                if(strcmpi(cmdname,"users")==0)
265                                {
266                                        int users = 0;
267                                        struct s_mapiterator* iter;
268
269                                        iter = mapit_getallusers();
270                                        for( mapit_first(iter); mapit_exists(iter); mapit_next(iter) )
271                                                users++;
272                                        mapit_free(iter);
273
274                                        sprintf(send_string, "PRIVMSG %s :Users Online: %d", irc_channel, users);
275                                        irc_send(send_string);
276                                }
277                                else // List all users online
278                                if(strcmpi(cmdname,"who")==0)
279                                {
280                                        int users = 0;
281                                        struct s_mapiterator* iter;
282                                        struct map_session_data* sd;
283
284                                        iter = mapit_getallusers();
285                                        for( mapit_first(iter); mapit_exists(iter); mapit_next(iter) )
286                                                users++;
287                                        mapit_free(iter);
288
289                                        if(users > 0)
290                                        {
291                                                sprintf(send_string,"NOTICE %s :%d Users Online",source_nick,users);
292                                                irc_send(send_string);
293
294                                                iter = mapit_getallusers();
295                                                for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
296                                                {
297                                                        sprintf(send_string,"NOTICE %s :Name: \"%s\"",source_nick,sd->status.name);
298                                                        irc_send(send_string);
299                                                }
300                                                mapit_free(iter);
301                                        }
302                                        else
303                                        {
304                                                sprintf(send_string,"NOTICE %s :No Users Online",source_nick);
305                                                irc_send(send_string);
306                                        }
307                                }
308                        }
309                        else // Refresh Names
310                        if((strcmpi(command,"join")==0)||(strcmpi(command,"part")==0)||(strcmpi(command,"mode")==0)||(strcmpi(command,"nick")==0))
311                        {
312                                ShowInfo("IRC: Refreshing User List");
313                                irc_rmnames();
314                                ShowMessage("...");
315                                sprintf(send_string,"NAMES %s",irc_channel);
316                                irc_send(send_string);
317                                ShowMessage("Done\n");
318                        }
319                        else // Autojoin on kick
320                        if((strcmpi(command,"kick")==0)&&(irc_autojoin==1))
321                        {
322                                sprintf(send_string, "JOIN %s %s", target, irc_channel_pass);
323                                irc_send(send_string);
324                        }
325                }
326                else // Names Reply
327                if((strcmpi(command,"353")==0))
328                {
329                        ShowInfo("IRC: NAMES received\n");
330                        parse_names_packet(incoming_string);
331                }
332        break;
333        }
334}
335
336int send_to_parser(int fd, char *input,char key[2])
337{
338        char *temp_string=NULL;
339        char *state_mgr=NULL;
340        int total_loops=0;
341
342        temp_string = strtok_r(input,key,&state_mgr);
343        while (temp_string != NULL)
344        {
345                total_loops = total_loops+1;
346                irc_parse_sub(fd,temp_string);
347                temp_string = strtok_r(NULL,key,&state_mgr);
348        }
349        return total_loops;
350}
351
352//NAMES Packet(353) parser
353int parse_names_packet(char *str)
354{
355        char *tok;
356        char source[256];
357        char numeric[10];
358        char target[256];
359        char channel[256];
360        char names[1024];
361
362        memset(source,'\0',256);
363        memset(numeric,'\0',10);
364        memset(target,'\0',256);
365        memset(channel,'\0',256);
366        memset(names,'\0',1024);
367
368        //TODO: fold this
369        tok=strtok(str,"\r\n");
370        sscanf(tok,":%255s %10s %255s %*1[=@] %255s :%1023[^\r\n]",source,numeric,target,channel,names);
371        if(strcmpi(numeric,"353")==0)
372                parse_names(names);
373
374        while((tok=strtok(NULL,"\r\n"))!=NULL)
375        {
376                sscanf(tok,":%255s %10s %255s %*1[=@] %255s :%1023[^\r\n]",source,numeric,target,channel,names);
377                if(strcmpi(numeric,"353")==0)
378                        parse_names(names);
379        }
380
381        return 0;
382}
383
384//User access level prefix parser
385int parse_names(char* str)
386{
387        //TODO: fold this copy-pasted junk
388        char* tok;
389        if (str == NULL) return 0; //Nothing to parse!
390        tok = strtok(str, " ");
391        switch(tok[0])
392        {
393                case '~': set_access(tok+1,ACCESS_OWNER); break;
394                case '&': set_access(tok+1,ACCESS_SOP); break;
395                case '@': set_access(tok+1,ACCESS_OP); break;
396                case '%': set_access(tok+1,ACCESS_HOP); break;
397                case '+': set_access(tok+1,ACCESS_VOICE); break;
398                default : set_access(tok,ACCESS_NORM); break;   
399        }
400
401        while((tok = strtok(NULL, " ")) != NULL)
402        {
403                switch(tok[0])
404                {
405                        case '~': set_access(tok+1,ACCESS_OWNER); break;
406                        case '&': set_access(tok+1,ACCESS_SOP); break;
407                        case '@': set_access(tok+1,ACCESS_OP); break;
408                        case '%': set_access(tok+1,ACCESS_HOP); break;
409                        case '+': set_access(tok+1,ACCESS_VOICE); break;
410                        default : set_access(tok,ACCESS_NORM); break;   
411                }
412        }
413       
414        return 1;
415}
416
417//Store user's access level
418int set_access(char *nick,int newlevel)
419{
420        int i;
421       
422        for(i = 0; i <= MAX_CHANNEL_USERS; i++) {
423                if(strcmpi(cd.user[i].name, nick)==0) {
424                        cd.user[i].level = newlevel;
425                        return 1;
426                }
427        }
428
429        strcpy(cd.user[last_cd_user].name, nick);
430        cd.user[last_cd_user].level = newlevel;
431        last_cd_user++;
432
433        return 0;
434}
435
436//Returns users access level
437int get_access(char *nick)
438{
439        int i;
440       
441        for(i = 0; i <= MAX_CHANNEL_USERS; i++)
442                if(strcmpi(cd.user[i].name, nick)==0)
443                        return (cd.user[i].level);
444
445        return -1;
446}
447
448int irc_rmnames()
449{
450        int i;
451        //TODO: why not just set the max counter to 0?
452        for(i = 0; i <= MAX_CHANNEL_USERS; i++)
453                cd.user[i].level=0;
454
455        last_cd_user = 0;
456        return 0;
457}
458
459int irc_read_conf(char *file)
460{
461        FILE *fp=NULL;
462        char w1[256];
463        char w2[256];
464        char path[256];
465        char row[1024];
466
467        memset(w1,'\0',256);
468        memset(w2,'\0',256);
469        memset(path,'\0',256);
470        memset(row,'\0',256);
471
472        sprintf(path,"conf/%s",file);
473
474        if(!(fp=fopen(path,"r"))) {
475                ShowError("Cannot find file: %s\n",path);
476                return 0;
477        }
478
479        while(fgets(row, sizeof(row), fp) != NULL)
480        {
481                if(row[0]=='/' && row[1]=='/')
482                        continue;
483
484                sscanf(row,"%[^:]: %255[^\r\n]",w1,w2);
485                if(strcmpi(w1,"use_irc")==0)
486                        use_irc = config_switch(w2);
487                else if(strcmpi(w1,"irc_server")==0)
488                        strcpy(irc_ip_str,w2);
489                else if(strcmpi(w1,"irc_port")==0)
490                        irc_port = atoi(w2);
491                else if(strcmpi(w1,"irc_autojoin")==0)
492                        irc_autojoin = atoi(w2);
493                else if(strcmpi(w1,"irc_channel")==0)
494                        strcpy(irc_channel,w2);
495                else if(strcmpi(w1,"irc_channel_pass")==0)
496                        strcpy(irc_channel_pass,w2);
497                else if(strcmpi(w1,"irc_trade_channel")==0)
498                        strcpy(irc_trade_channel,w2);
499                else if(strcmpi(w1,"irc_nick")==0)
500                        strcpy(irc_nick,w2);
501                else if(strcmpi(w1,"irc_pass")==0) {
502                        if(strcmpi(w2,"0")!=0)
503                                strcpy(irc_password,w2);
504                }
505        }
506
507        ShowInfo("IRC Config read successfully\n");
508
509        return 1;
510}
511
512void do_init_irc(void)
513{
514        if(!use_irc)
515                return;
516
517        irc_ip = host2ip(irc_ip_str);
518        if (!irc_ip)
519        {
520                ShowError("Unable to resolve %s! Cannot connect to IRC server, disabling irc_bot.\n", irc_ip_str);
521                use_irc = 0;
522                return;
523        }
524
525        irc_connect_timer(0, 0, 0, 0);
526
527        add_timer_func_list(irc_connect_timer, "irc_connect_timer");
528        add_timer_func_list(irc_keepalive_timer, "irc_keepalive_timer");
529        add_timer(gettick() + 30000, irc_keepalive_timer, 0, 0);
530}
531
532void do_final_irc(void)
533{
534
535}
Note: See TracBrowser for help on using the browser.