/[LeafOK_CVS]/pvpgn-1.7.4/src/bnetd/irc.c
ViewVC logotype

Contents of /pvpgn-1.7.4/src/bnetd/irc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (show annotations) (vendor branch)
Tue Jun 6 03:41:37 2006 UTC (19 years, 9 months ago) by sysadm
Branch: GNU, MAIN
CVS Tags: pvpgn_1-7-4-0_MIL, arelease, HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
no message

1 /*
2 * Copyright (C) 2001 Marco Ziech (mmz@gmx.net)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include "common/setup_before.h"
20 #ifdef STDC_HEADERS
21 # include <stdlib.h>
22 #else
23 # ifdef HAVE_MALLOC_H
24 # include <malloc.h>
25 # endif
26 #endif
27 #ifdef HAVE_STRING_H
28 # include <string.h>
29 #else
30 # ifdef HAVE_STRINGS_H
31 # include <strings.h>
32 # endif
33 # ifdef HAVE_MEMORY_H
34 # include <memory.h>
35 # endif
36 #endif
37 #include "compat/strdup.h"
38 #include <errno.h>
39 #include "compat/strerror.h"
40 #ifdef TIME_WITH_SYS_TIME
41 # include <sys/time.h>
42 # include <time.h>
43 #else
44 # ifdef HAVE_SYS_TIME_H
45 # include <sys/time.h>
46 # else
47 # include <time.h>
48 # endif
49 #endif
50 #include "common/irc_protocol.h"
51 #include "common/packet.h"
52 #include "common/eventlog.h"
53 #include "connection.h"
54 #include "common/bn_type.h"
55 #include "common/field_sizes.h"
56 #include "common/addr.h"
57 #include "common/version.h"
58 #include "common/queue.h"
59 #include "common/list.h"
60 #include "common/bnethash.h"
61 #include "common/bnethashconv.h"
62 #include "common/tag.h"
63 #include "message.h"
64 #include "account.h"
65 #include "account_wrap.h"
66 #include "channel.h"
67 #include "irc.h"
68 #include "prefs.h"
69 #include "server.h"
70 #include "tick.h"
71 #include "message.h"
72 #include "command_groups.h"
73 #include "common/util.h"
74 #include "common/xalloc.h"
75 #include "common/setup_after.h"
76
77 typedef struct {
78 char const * nick;
79 char const * user;
80 char const * host;
81 } t_irc_message_from;
82
83
84 static char ** irc_split_elems(char * list, int separator, int ignoreblank);
85 static int irc_unget_elems(char ** elems);
86 static char * irc_message_preformat(t_irc_message_from const * from, char const * command, char const * dest, char const * text);
87
88 extern int irc_send_cmd(t_connection * conn, char const * command, char const * params)
89 {
90 t_packet * p;
91 char data[MAX_IRC_MESSAGE_LEN+1];
92 int len;
93 char const * ircname = server_get_name();
94 char const * nick;
95
96 if (!conn) {
97 eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
98 return -1;
99 }
100 if (!command) {
101 eventlog(eventlog_level_error,__FUNCTION__,"got NULL command");
102 return -1;
103 }
104 if (!(p = packet_create(packet_class_raw))) {
105 eventlog(eventlog_level_error,__FUNCTION__,"could not create packet");
106 return -1;
107 }
108
109 nick = conn_get_loggeduser(conn);
110 if (!nick)
111 nick = ""; /* FIXME: Is this good? */
112 /* snprintf isn't portable -> check message length first */
113 if (params) {
114 len = 1+strlen(ircname)+1+strlen(command)+1+strlen(nick)+1+strlen(params)+2;
115 if (len > MAX_IRC_MESSAGE_LEN)
116 {
117 eventlog(eventlog_level_error,__FUNCTION__,"message to send is too large (%d bytes)",len);
118 return -1;
119 }
120 else
121 sprintf(data,":%s %s %s %s\r\n",ircname,command,nick,params);
122 } else {
123 len = 1+strlen(ircname)+1+strlen(command)+1+strlen(nick)+1+2;
124 if (len > MAX_IRC_MESSAGE_LEN)
125 {
126 eventlog(eventlog_level_error,__FUNCTION__,"message to send is too large (%d bytes)",len);
127 return -1;
128 }
129 else
130 sprintf(data,":%s %s %s\r\n",ircname,command,nick);
131 }
132 packet_set_size(p,0);
133 packet_append_data(p,data,len);
134 // eventlog(eventlog_level_debug,__FUNCTION__,"[%d] sent \"%s\"",conn_get_socket(conn),data);
135 conn_push_outqueue(conn,p);
136 packet_del_ref(p);
137 return 0;
138 }
139
140 extern int irc_send(t_connection * conn, int code, char const * params)
141 {
142 char temp[4]; /* '000\0' */
143
144 if (!conn) {
145 eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
146 return -1;
147 }
148 if ((code>999)||(code<0)) { /* more than 3 digits or negative */
149 eventlog(eventlog_level_error,__FUNCTION__,"invalid message code (%d)",code);
150 return -1;
151 }
152 sprintf(temp,"%03u",code);
153 return irc_send_cmd(conn,temp,params);
154 }
155
156 extern int irc_send_cmd2(t_connection * conn, char const * prefix, char const * command, char const * postfix, char const * comment)
157 {
158 t_packet * p;
159 char data[MAX_IRC_MESSAGE_LEN+1];
160 int len;
161
162 if (!conn) {
163 eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
164 return -1;
165 }
166 if (!prefix)
167 {
168 eventlog(eventlog_level_error,__FUNCTION__,"got NULL prefix");
169 return -1;
170 }
171 if (!command) {
172 eventlog(eventlog_level_error,__FUNCTION__,"got NULL command");
173 return -1;
174 }
175 if (!postfix)
176 {
177 eventlog(eventlog_level_error,__FUNCTION__,"got NULL postfix");
178 return -1;
179 }
180
181 if (!(p = packet_create(packet_class_raw))) {
182 eventlog(eventlog_level_error,__FUNCTION__,"could not create packet");
183 return -1;
184 }
185
186 if (comment) {
187 len = 1+strlen(prefix)+1+strlen(command)+1+strlen(postfix)+2+strlen(comment)+1+2;
188 if (len > MAX_IRC_MESSAGE_LEN)
189 {
190 eventlog(eventlog_level_error,__FUNCTION__,"message to send is too large (%d bytes)",len);
191 return -1;
192 }
193 else
194 sprintf(data,":%s %s %s :%s\r\n",prefix,command,postfix,comment);
195 } else {
196 len = 1+strlen(prefix)+1+strlen(command)+1+strlen(postfix)+1+2;
197 if (len > MAX_IRC_MESSAGE_LEN)
198 {
199 eventlog(eventlog_level_error,__FUNCTION__,"message to send is too large (%d bytes)",len);
200 return -1;
201 }
202 else
203 sprintf(data,":%s %s %s\r\n",prefix,command,postfix);
204 }
205 packet_set_size(p,0);
206 packet_append_data(p,data,len);
207 // eventlog(eventlog_level_debug,__FUNCTION__,"[%d] sent \"%s\"",conn_get_socket(conn),data);
208 conn_push_outqueue(conn,p);
209 packet_del_ref(p);
210 return 0;
211 }
212
213 extern int irc_send_ping(t_connection * conn)
214 {
215 t_packet * p;
216 char data[MAX_IRC_MESSAGE_LEN];
217
218 if (!conn) {
219 eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
220 return -1;
221 }
222 if (!(p = packet_create(packet_class_raw))) {
223 eventlog(eventlog_level_error,__FUNCTION__,"could not create packet");
224 return -1;
225 }
226 conn_set_ircping(conn,get_ticks());
227 if (conn_get_state(conn)==conn_state_bot_username)
228 sprintf(data,"PING :%u\r\n",conn_get_ircping(conn)); /* Undernet doesn't reveal the servername yet ... so do we */
229 else if ((6+strlen(server_get_name())+2+1)<=MAX_IRC_MESSAGE_LEN)
230 sprintf(data,"PING :%s\r\n",server_get_name());
231 else
232 eventlog(eventlog_level_error,__FUNCTION__,"maximum message length exceeded");
233 eventlog(eventlog_level_debug,__FUNCTION__,"[%d] sent \"%s\"",conn_get_socket(conn),data);
234 packet_set_size(p,0);
235 packet_append_data(p,data,strlen(data));
236 conn_push_outqueue(conn,p);
237 packet_del_ref(p);
238 return 0;
239 }
240
241 extern int irc_send_pong(t_connection * conn, char const * params)
242 {
243 t_packet * p;
244 char data[MAX_IRC_MESSAGE_LEN];
245
246 if (!conn) {
247 eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
248 return -1;
249 }
250 if ((1+strlen(server_get_name())+1+4+1+strlen(server_get_name())+((params)?(2+strlen(params)):(0))+2+1) > MAX_IRC_MESSAGE_LEN) {
251 eventlog(eventlog_level_error,__FUNCTION__,"max message length exceeded");
252 return -1;
253 }
254 if (!(p = packet_create(packet_class_raw))) {
255 eventlog(eventlog_level_error,__FUNCTION__,"could not create packet");
256 return -1;
257 }
258 if (params)
259 sprintf(data,":%s PONG %s :%s\r\n",server_get_name(),server_get_name(),params);
260 else
261 sprintf(data,":%s PONG %s\r\n",server_get_name(),server_get_name());
262 eventlog(eventlog_level_debug,__FUNCTION__,"[%d] sent \"%s\"",conn_get_socket(conn),data);
263 packet_set_size(p,0);
264 packet_append_data(p,data,strlen(data));
265 conn_push_outqueue(conn,p);
266 packet_del_ref(p);
267 return 0;
268 }
269
270 extern int irc_authenticate(t_connection * conn, char const * passhash)
271 {
272 t_hash h1;
273 t_hash h2;
274 t_account * a;
275 char const * temphash;
276 char const * username;
277
278 if (!conn) {
279 eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
280 return 0;
281 }
282 if (!passhash) {
283 eventlog(eventlog_level_error,__FUNCTION__,"got NULL passhash");
284 return 0;
285 }
286 username = conn_get_loggeduser(conn);
287 if (!username) {
288 /* redundant sanity check */
289 eventlog(eventlog_level_error,__FUNCTION__,"got NULL conn->protocol.loggeduser");
290 return 0;
291 }
292 a = accountlist_find_account(username);
293 if (!a) {
294 irc_send_cmd(conn,"NOTICE",":Authentication failed."); /* user does not exist */
295 return 0;
296 }
297
298 if (connlist_find_connection_by_account(a) && prefs_get_kick_old_login()==0)
299 {
300 irc_send_cmd(conn,"NOTICE",":Authentication rejected (already logged in) ");
301 }
302 else if (account_get_auth_lock(a)==1)
303 {
304 irc_send_cmd(conn,"NOTICE",":Authentication rejected (account is locked) ");
305 }
306 else
307 {
308 hash_set_str(&h1,passhash);
309 temphash = account_get_pass(a);
310 hash_set_str(&h2,temphash);
311 if (hash_eq(h1,h2)) {
312 conn_login(conn,a,username);
313 conn_set_state(conn,conn_state_loggedin);
314 /* FIXME: set clienttag to "ircd" or something (and make an icon) */
315 conn_set_clienttag(conn,CLIENTTAG_BNCHATBOT_UINT); /* CHAT hope here is ok */
316 irc_send_cmd(conn,"NOTICE",":Authentication successful. You are now logged in.");
317 return 1;
318 } else {
319 irc_send_cmd(conn,"NOTICE",":Authentication failed."); /* wrong password */
320 conn_increment_passfail_count(conn);
321 }
322 }
323 return 0;
324 }
325
326 extern int irc_welcome(t_connection * conn)
327 {
328 char temp[MAX_IRC_MESSAGE_LEN];
329 time_t temptime;
330 char const * tempname;
331 char const * temptimestr;
332 char const * filename;
333 FILE *fp;
334 char * line, * formatted_line;
335 char send_line[MAX_IRC_MESSAGE_LEN];
336 char motd_failed = 0;
337
338 if (!conn) {
339 eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
340 return -1;
341 }
342
343 tempname = conn_get_loggeduser(conn);
344
345
346 if ((34+strlen(tempname)+1)<=MAX_IRC_MESSAGE_LEN)
347 sprintf(temp,":Welcome to the BNETD IRC Network %s",tempname);
348 else
349 sprintf(temp,":Maximum length exceeded");
350 irc_send(conn,RPL_WELCOME,temp);
351
352 if ((14+strlen(server_get_name())+10+strlen(PVPGN_SOFTWARE" "PVPGN_VERSION)+1)<=MAX_IRC_MESSAGE_LEN)
353 sprintf(temp,":Your host is %s, running "PVPGN_SOFTWARE" "PVPGN_VERSION,server_get_name());
354 else
355 sprintf(temp,":Maximum length exceeded");
356 irc_send(conn,RPL_YOURHOST,temp);
357
358 temptime = server_get_starttime(); /* FIXME: This should be build time */
359 temptimestr = ctime(&temptime);
360 if ((25+strlen(temptimestr)+1)<=MAX_IRC_MESSAGE_LEN)
361 sprintf(temp,":This server was created %s",temptimestr); /* FIXME: is ctime() portable? */
362 else
363 sprintf(temp,":Maximum length exceeded");
364 irc_send(conn,RPL_CREATED,temp);
365
366 if ((strlen(server_get_name())+7+strlen(PVPGN_SOFTWARE" "PVPGN_VERSION)+9+1)<=MAX_IRC_MESSAGE_LEN)
367 sprintf(temp,"%s "PVPGN_SOFTWARE" "PVPGN_VERSION" aroO Oon",server_get_name()); /* FIXME: be honest about modes :) */
368 else
369 sprintf(temp,":Maximum length exceeded");
370 irc_send(conn,RPL_MYINFO,temp);
371 /* 251 is here */
372 /* 255 is here */
373 /* FIXME: show a real MOTD */
374 if ((3+strlen(server_get_name())+22+1)<=MAX_IRC_MESSAGE_LEN)
375 sprintf(temp,":- %s Message of the day - ",server_get_name());
376 else
377 sprintf(temp,":Maximum length exceeded");
378
379 irc_send(conn,RPL_MOTDSTART,temp);
380
381 if ((filename = prefs_get_motdfile()))
382 {
383 if ((fp = fopen(filename,"r")))
384 {
385
386 while ((line=file_get_line(fp)))
387 {
388
389 if ((formatted_line = message_format_line(conn,line)))
390 {
391 formatted_line[0]=' ';
392 sprintf(send_line,":-%s",formatted_line);
393 irc_send(conn,RPL_MOTD,send_line);
394 xfree(formatted_line);
395 }
396 }
397
398 file_get_line(NULL); // clear file_get_line buffer
399 fclose(fp);
400 }
401 else motd_failed = 1;
402 }
403 else
404 motd_failed = 1;
405
406 if (motd_failed)
407 {
408 irc_send(conn,RPL_MOTD,":- Failed to load motd, sending default motd ");
409 irc_send(conn,RPL_MOTD,":- ====================================================== ");
410 irc_send(conn,RPL_MOTD,":- http://www.pvpgn.org ");
411 irc_send(conn,RPL_MOTD,":- ====================================================== ");
412 }
413 irc_send(conn,RPL_ENDOFMOTD,":End of /MOTD command");
414 irc_send_cmd(conn,"NOTICE",":This is an experimental service.");
415 conn_set_state(conn,conn_state_bot_password);
416 if (connlist_find_connection_by_accountname(conn_get_loggeduser(conn))) {
417 irc_send_cmd(conn,"NOTICE","This account is allready logged in, use another account.");
418 return -1;
419 }
420 if (conn_get_ircpass(conn)) {
421 irc_send_cmd(conn,"NOTICE",":Trying to authenticate with PASS ...");
422 irc_authenticate(conn,conn_get_ircpass(conn));
423 } else {
424 irc_send_cmd(conn,"NOTICE",":No PASS command received. Please identify yourself by /msg NICKSERV identify <password>.");
425 }
426 return 0;
427 }
428
429 /* Channel name conversion rules: */
430 /* Not allowed in IRC (RFC2812): NUL, BELL, CR, LF, ' ', ':' and ','*/
431 /* ' ' -> '_' */
432 /* '_' -> '%_' */
433 /* '%' -> '%%' */
434 /* '\b' -> '%b' */
435 /* '\n' -> '%n' */
436 /* '\r' -> '%r' */
437 /* ':' -> '%=' */
438 /* ',' -> '%-' */
439 /* In IRC a channel can be specified by '#'+channelname or '!'+channelid */
440
441 extern char const * irc_convert_channel(t_channel const * channel)
442 {
443 char const * bname;
444 static char out[CHANNEL_NAME_LEN];
445 unsigned int outpos;
446 int i;
447
448 if (!channel)
449 return "*";
450
451 memset(out,0,sizeof(out));
452 out[0] = '#';
453 outpos = 1;
454 bname = channel_get_name(channel);
455 for (i=0; bname[i]!='\0'; i++) {
456 if (bname[i]==' ') {
457 out[outpos++] = '_';
458 } else if (bname[i]=='_') {
459 out[outpos++] = '%';
460 out[outpos++] = '_';
461 } else if (bname[i]=='%') {
462 out[outpos++] = '%';
463 out[outpos++] = '%';
464 } else if (bname[i]=='\b') {
465 out[outpos++] = '%';
466 out[outpos++] = 'b';
467 } else if (bname[i]=='\n') {
468 out[outpos++] = '%';
469 out[outpos++] = 'n';
470 } else if (bname[i]=='\r') {
471 out[outpos++] = '%';
472 out[outpos++] = 'r';
473 } else if (bname[i]==':') {
474 out[outpos++] = '%';
475 out[outpos++] = '=';
476 } else if (bname[i]==',') {
477 out[outpos++] = '%';
478 out[outpos++] = '-';
479 } else {
480 out[outpos++] = bname[i];
481 }
482 if ((outpos+2)>=(sizeof(out))) {
483 sprintf(out,"!%u",channel_get_channelid(channel));
484 return out;
485 }
486 }
487 return out;
488 }
489
490 extern char const * irc_convert_ircname(char const * pircname)
491 {
492 static char out[CHANNEL_NAME_LEN];
493 unsigned int outpos;
494 int special;
495 int i;
496 char const * ircname = pircname + 1;
497
498 if (!ircname) {
499 eventlog(eventlog_level_error,__FUNCTION__,"got NULL ircname");
500 return NULL;
501 }
502
503 outpos = 0;
504 memset(out,0,sizeof(out));
505 special = 0;
506 if (pircname[0]=='!') {
507 t_channel * channel;
508
509 channel = channellist_find_channel_bychannelid(atoi(ircname));
510 if (channel)
511 return channel_get_name(channel);
512 else
513 return NULL;
514 } else if (pircname[0]!='#') {
515 return NULL;
516 }
517 for (i=0; ircname[i]!='\0'; i++) {
518 if (ircname[i]=='_') {
519 out[outpos++] = ' ';
520 } else if (ircname[i]=='%') {
521 if (special) {
522 out[outpos++] = '%';
523 special = 0;
524 } else {
525 special = 1;
526 }
527 } else if (special) {
528 if (ircname[i]=='_') {
529 out[outpos++] = '_';
530 } else if (ircname[i]=='b') {
531 out[outpos++] = '\b';
532 } else if (ircname[i]=='n') {
533 out[outpos++] = '\n';
534 } else if (ircname[i]=='r') {
535 out[outpos++] = '\r';
536 } else if (ircname[i]=='=') {
537 out[outpos++] = ':';
538 } else if (ircname[i]=='-') {
539 out[outpos++] = ',';
540 } else {
541 /* maybe it's just a typo :) */
542 out[outpos++] = '%';
543 out[outpos++] = ircname[i];
544 }
545 } else {
546 out[outpos++] = ircname[i];
547 }
548 if ((outpos+2)>=(sizeof(out))) {
549 return NULL;
550 }
551 }
552 return out;
553 }
554
555 /* splits an string list into its elements */
556 /* (list will be modified) */
557 static char ** irc_split_elems(char * list, int separator, int ignoreblank)
558 {
559 int i;
560 int count;
561 char ** out;
562
563 if (!list) {
564 eventlog(eventlog_level_error,__FUNCTION__,"got NULL list");
565 return NULL;
566 }
567
568 for (count=0,i=0;list[i]!='\0';i++) {
569 if (list[i]==separator) {
570 count++;
571 if (ignoreblank) {
572 /* ignore more than one separators "in a row" */
573 while ((list[i+1]!='\0')&&(list[i]==separator)) i++;
574 }
575 }
576 }
577 count++; /* count separators -> we have one more element ... */
578 /* we also need a terminating element */
579 out = xmalloc((count+1)*sizeof(char *));
580
581 out[0] = list;
582 if (count>1) {
583 for (i=1;i<count;i++) {
584 out[i] = strchr(out[i-1],separator);
585 if (!out[i]) {
586 eventlog(eventlog_level_error,__FUNCTION__,"BUG: wrong number of separators");
587 xfree(out);
588 return NULL;
589 }
590 if (ignoreblank)
591 while ((*out[i]+1)==separator) out[i]++;
592 *out[i]++ = '\0';
593 }
594 if ((ignoreblank)&&(out[count-1])&&(*out[count-1]=='\0')) {
595 out[count-1] = NULL; /* last element is blank */
596 }
597 } else if ((ignoreblank)&&(*out[0]=='\0')) {
598 out[0] = NULL; /* now we have 2 terminators ... never mind */
599 }
600 out[count] = NULL; /* terminating element */
601 return out;
602 }
603
604 static int irc_unget_elems(char ** elems)
605 {
606 if (!elems) {
607 eventlog(eventlog_level_error,__FUNCTION__,"got NULL elems");
608 return -1;
609 }
610 xfree(elems);
611 return 0;
612 }
613
614 extern char ** irc_get_listelems(char * list)
615 {
616 return irc_split_elems(list,',',0);
617 }
618
619 extern int irc_unget_listelems(char ** elems)
620 {
621 return irc_unget_elems(elems);
622 }
623
624 extern char ** irc_get_paramelems(char * list)
625 {
626 return irc_split_elems(list,' ',1);
627 }
628
629 extern int irc_unget_paramelems(char ** elems)
630 {
631 return irc_unget_elems(elems);
632 }
633
634 static char * irc_message_preformat(t_irc_message_from const * from, char const * command, char const * dest, char const * text)
635 {
636 char * myfrom;
637 char const * mydest = "";
638 char const * mytext = "";
639 int len;
640 char * msg;
641
642 if (!command) {
643 eventlog(eventlog_level_error,__FUNCTION__,"got NULL command");
644 return NULL;
645 }
646 if (from) {
647 if ((!from->nick)||(!from->user)||(!from->host)) {
648 eventlog(eventlog_level_error,__FUNCTION__,"got malformed from");
649 return NULL;
650 }
651 myfrom = xmalloc(strlen(from->nick)+1+strlen(from->user)+1+strlen(from->host)+1); /* nick + "!" + user + "@" + host + "\0" */
652 sprintf(myfrom,"%s!%s@%s",from->nick,from->user,from->host);
653 } else
654 myfrom = xstrdup(server_get_name());
655 if (dest)
656 mydest = dest;
657 if (text)
658 mytext = text;
659
660 len = 1+strlen(myfrom)+1+
661 strlen(command)+1+
662 strlen(mydest)+1+
663 1+strlen(mytext)+1;
664
665
666 msg = xmalloc(len);
667 sprintf(msg,":%s\n%s\n%s\n%s",myfrom,command,mydest,mytext);
668 xfree(myfrom);
669 return msg;
670 }
671
672 extern int irc_message_postformat(t_packet * packet, t_connection const * dest)
673 {
674 int len;
675 /* the four elements */
676 char * e1;
677 char * e1_2;
678 char * e2;
679 char * e3;
680 char * e4;
681 char const * tname = NULL;
682 char const * toname = "AUTH"; /* fallback name */
683
684 if (!packet) {
685 eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
686 return -1;
687 }
688 if (!dest) {
689 eventlog(eventlog_level_error,__FUNCTION__,"got NULL dest");
690 return -1;
691 }
692
693 e1 = packet_get_raw_data(packet,0);
694 e2 = strchr(e1,'\n');
695 if (!e2) {
696 eventlog(eventlog_level_warn,__FUNCTION__,"malformed message (e2 missing)");
697 return -1;
698 }
699 *e2++ = '\0';
700 e3 = strchr(e2,'\n');
701 if (!e3) {
702 eventlog(eventlog_level_warn,__FUNCTION__,"malformed message (e3 missing)");
703 return -1;
704 }
705 *e3++ = '\0';
706 e4 = strchr(e3,'\n');
707 if (!e4) {
708 eventlog(eventlog_level_warn,__FUNCTION__,"malformed message (e4 missing)");
709 return -1;
710 }
711 *e4++ = '\0';
712
713 if (prefs_get_hide_addr() && !(account_get_command_groups(conn_get_account(dest)) & command_get_group("/admin-addr")))
714 {
715 e1_2 = strchr(e1,'@');
716 if (e1_2)
717 {
718 *e1_2++ = '\0';
719 }
720 }
721 else
722 e1_2 = NULL;
723
724 if (e3[0]=='\0') { /* fill in recipient */
725 if ((tname = conn_get_chatname(dest)))
726 toname = tname;
727 } else
728 toname = e3;
729
730 if (strcmp(toname,"\r")==0) {
731 toname = ""; /* HACK: the target field is really empty */
732 }
733
734 len = (strlen(e1)+1+strlen(e2)+1+strlen(toname)+1+strlen(e4)+2+1);
735 if (len<=MAX_IRC_MESSAGE_LEN) {
736 char msg[MAX_IRC_MESSAGE_LEN+1];
737
738 if (e1_2)
739 sprintf(msg,"%s@hidden %s %s %s\r\n",e1,e2,toname,e4);
740 else
741 sprintf(msg,"%s %s %s %s\r\n",e1,e2,toname,e4);
742 eventlog(eventlog_level_debug,__FUNCTION__,"sent \"%s\"",msg);
743 packet_set_size(packet,0);
744 packet_append_data(packet,msg,strlen(msg));
745 if (tname)
746 conn_unget_chatname(dest,tname);
747 return 0;
748 } else {
749 /* FIXME: split up message? */
750 eventlog(eventlog_level_warn,__FUNCTION__,"maximum IRC message length exceeded");
751 if (tname)
752 conn_unget_chatname(dest,tname);
753 return -1;
754 }
755 }
756
757 extern int irc_message_format(t_packet * packet, t_message_type type, t_connection * me, t_connection * dst, char const * text, unsigned int dstflags)
758 {
759 char * msg;
760 char const * ctag;
761 t_irc_message_from from;
762
763 if (!packet)
764 {
765 eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
766 return -1;
767 }
768
769 msg = NULL;
770 ctag = clienttag_uint_to_str(conn_get_clienttag(me));
771
772 switch (type)
773 {
774 /* case message_type_adduser: this is sent manually in handle_irc */
775 case message_type_adduser:
776 /* when we do it somewhere else, then we can also make sure to not get our logs spammed */
777 break;
778 case message_type_join:
779 from.nick = conn_get_chatname(me);
780 from.user = ctag;
781 from.host = addr_num_to_ip_str(conn_get_addr(me));
782 msg = irc_message_preformat(&from,"JOIN","\r",irc_convert_channel(conn_get_channel(me)));
783 conn_unget_chatname(me,from.nick);
784 break;
785 case message_type_part:
786 from.nick = conn_get_chatname(me);
787 from.user = ctag;
788 from.host = addr_num_to_ip_str(conn_get_addr(me));
789 msg = irc_message_preformat(&from,"PART","\r",irc_convert_channel(conn_get_channel(me)));
790 conn_unget_chatname(me,from.nick);
791 break;
792 case message_type_talk:
793 case message_type_whisper:
794 {
795 char const * dest;
796 char temp[MAX_IRC_MESSAGE_LEN];
797 from.nick = conn_get_chatname(me);
798 from.user = ctag;
799 from.host = addr_num_to_ip_str(conn_get_addr(me));
800 if (type==message_type_talk)
801 dest = irc_convert_channel(conn_get_channel(me)); /* FIXME: support more channels and choose right one! */
802 else
803 dest = ""; /* will be replaced with username in postformat */
804 sprintf(temp,":%s",text);
805 msg = irc_message_preformat(&from,"PRIVMSG",dest,temp);
806 conn_unget_chatname(me,from.nick);
807 }
808 break;
809 case message_type_emote:
810 {
811 char const * dest;
812 char temp[MAX_IRC_MESSAGE_LEN];
813
814 /* "\001ACTION " + text + "\001" + \0 */
815 if ((8+strlen(text)+1+1)<=MAX_IRC_MESSAGE_LEN) {
816 sprintf(temp,":\001ACTION %s\001",text);
817 } else {
818 sprintf(temp,":\001ACTION (maximum message length exceeded)\001");
819 }
820 from.nick = conn_get_chatname(me);
821 from.user = ctag;
822 from.host = addr_num_to_ip_str(conn_get_addr(me));
823 /* FIXME: also supports whisper emotes? */
824 dest = irc_convert_channel(conn_get_channel(me)); /* FIXME: support more channels and choose right one! */
825 msg = irc_message_preformat(&from,"PRIVMSG",dest,temp);
826 conn_unget_chatname(me,from.nick);
827 }
828 break;
829 case message_type_broadcast:
830 case message_type_info:
831 case message_type_error:
832 {
833 char temp[MAX_IRC_MESSAGE_LEN];
834 sprintf(temp,":%s",text);
835 msg = irc_message_preformat(NULL,"NOTICE",NULL,temp);
836 }
837 break;
838 case message_type_channel:
839 /* ignore it */
840 break;
841 case message_type_mode:
842 from.nick = conn_get_chatname(me);
843 from.user = ctag;
844 from.host = addr_num_to_ip_str(conn_get_addr(me));
845 msg = irc_message_preformat(&from,"MODE","\r",text);
846 conn_unget_chatname(me,from.nick);
847 break;
848 default:
849 eventlog(eventlog_level_warn,__FUNCTION__,"%d not yet implemented",type);
850 return -1;
851 }
852
853 if (msg) {
854 packet_append_string(packet,msg);
855 xfree(msg);
856 return 0;
857 }
858 return -1;
859 }
860
861 extern int irc_send_rpl_namreply(t_connection * c, t_channel const * channel)
862 {
863 char temp[MAX_IRC_MESSAGE_LEN];
864 char const * ircname;
865 int first = 1;
866 t_connection * m;
867
868 if (!c) {
869 eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
870 return -1;
871 }
872 if (!channel) {
873 eventlog(eventlog_level_error,__FUNCTION__,"got NULL channel");
874 return -1;
875 }
876 memset(temp,0,sizeof(temp));
877 ircname = irc_convert_channel(channel);
878 if (!ircname) {
879 eventlog(eventlog_level_error,__FUNCTION__,"channel has NULL ircname");
880 return -1;
881 }
882 /* '@' = secret; '*' = private; '=' = public */
883 if ((1+1+strlen(ircname)+2+1)<=MAX_IRC_MESSAGE_LEN) {
884 sprintf(temp,"%c %s :",((channel_get_permanent(channel))?('='):('*')),ircname);
885 } else {
886 eventlog(eventlog_level_warn,__FUNCTION__,"maximum message length exceeded");
887 return -1;
888 }
889 /* FIXME: Add per user flags (@(op) and +(voice))*/
890 for (m = channel_get_first(channel);m;m = channel_get_next()) {
891 char const * name = conn_get_chatname(m);
892 char flg[5] = "";
893 unsigned int flags;
894
895 if (!name)
896 continue;
897 flags = conn_get_flags(m);
898 if (flags & MF_BLIZZARD)
899 strcat(flg,"@");
900 else if ((flags & MF_BNET) || (flags & MF_GAVEL))
901 strcat(flg,"%");
902 else if (flags & MF_VOICE)
903 strcat(flg,"+");
904 if ((strlen(temp)+((!first)?(1):(0))+strlen(flg)+strlen(name)+1)<=sizeof(temp)) {
905 if (!first) strcat(temp," ");
906 strcat(temp,flg);
907 strcat(temp,name);
908 first = 0;
909 }
910 conn_unget_chatname(m,name);
911 }
912 irc_send(c,RPL_NAMREPLY,temp);
913 return 0;
914 }
915
916 static int irc_who_connection(t_connection * dest, t_connection * c)
917 {
918 t_account * a;
919 char const * tempuser;
920 char const * tempowner;
921 char const * tempname;
922 char const * tempip;
923 char const * tempflags = "@"; /* FIXME: that's dumb */
924 char temp[MAX_IRC_MESSAGE_LEN];
925 char const * tempchannel;
926
927 if (!dest) {
928 eventlog(eventlog_level_error,__FUNCTION__,"got NULL destination");
929 return -1;
930 }
931 if (!c) {
932 eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
933 return -1;
934 }
935 a = conn_get_account(c);
936 if (!(tempuser = clienttag_uint_to_str(conn_get_clienttag(c))))
937 {
938 eventlog(eventlog_level_error,__FUNCTION__,"got NULL clienttag (tempuser)");
939 return -1;
940 }
941 if (!(tempowner = account_get_ll_owner(a)))
942 {
943 eventlog(eventlog_level_error,__FUNCTION__,"got NULL ll_owner (tempowner)");
944 return -1;
945 }
946 if (!(tempname = conn_get_username(c)))
947 {
948 eventlog(eventlog_level_error,__FUNCTION__,"got NULL username (tempname)");
949 return -1;
950 }
951 if (!(tempip = addr_num_to_ip_str(conn_get_addr(c))))
952 {
953 eventlog(eventlog_level_error,__FUNCTION__,"got NULL addr (tempip)");
954 return -1;
955 }
956 if (!(tempchannel = irc_convert_channel(conn_get_channel(c))))
957 {
958 eventlog(eventlog_level_error,__FUNCTION__,"got NULL channel (tempchannel)");
959 return -1;
960 }
961 if ((strlen(tempchannel)+1+strlen(tempuser)+1+strlen(tempip)+1+strlen(server_get_name())+1+strlen(tempname)+1+1+strlen(tempflags)+4+strlen(tempowner)+1)>MAX_IRC_MESSAGE_LEN) {
962 eventlog(eventlog_level_info,__FUNCTION__,"WHO reply too long - skip");
963 return -1;
964 } else
965 sprintf(temp,"%s %s %s %s %s %c%s :0 %s",tempchannel,tempuser,tempip,server_get_name(),tempname,'H',tempflags,tempowner);
966 irc_send(dest,RPL_WHOREPLY,temp);
967 return 0;
968 }
969
970 extern int irc_who(t_connection * c, char const * name)
971 {
972 /* FIXME: support wildcards! */
973
974 if (!c) {
975 eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
976 return -1;
977 }
978 if (!name) {
979 eventlog(eventlog_level_error,__FUNCTION__,"got NULL name");
980 return -1;
981 }
982 if ((name[0]=='#')||(name[0]=='&')||(name[0]=='!')) {
983 /* it's a channel */
984 t_connection * info;
985 t_channel * channel;
986 char const * ircname;
987
988 ircname = irc_convert_ircname(name);
989 channel = channellist_find_channel_by_name(ircname,NULL,NULL);
990 if (!channel) {
991 char temp[MAX_IRC_MESSAGE_LEN];
992
993 if ((strlen(":No such channel")+1+strlen(name)+1)<=MAX_IRC_MESSAGE_LEN) {
994 sprintf(temp,":No such channel %s",name);
995 irc_send(c,ERR_NOSUCHCHANNEL,temp);
996 } else {
997 irc_send(c,ERR_NOSUCHCHANNEL,":No such channel");
998 }
999 return 0;
1000 }
1001 for (info = channel_get_first(channel);info;info = channel_get_next()) {
1002 irc_who_connection(c,info);
1003 }
1004 } else {
1005 /* it's just one user */
1006 t_connection * info;
1007
1008 if ((info = connlist_find_connection_by_accountname(name)))
1009 return irc_who_connection(c,info);
1010 }
1011 return 0;
1012 }
1013

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1