irc.c 13 KB

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