irc.c 12 KB

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