1 /*
2  * Copyright (C) 1998  Mark Baysinger (mbaysing@ucsd.edu)
3  * Copyright (C) 1998,1999,2001,2002  Ross Combs (rocombs@cs.nmsu.edu)
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  */
19 #define MESSAGE_INTERNAL_ACCESS
20 #include "common/setup_before.h"
21 #include <stdio.h>
22 #ifdef HAVE_STDDEF_H
23 # include <stddef.h>
24 #else
25 # ifndef NULL
26 #  define NULL ((void *)0)
27 # endif
28 #endif
29 #ifdef STDC_HEADERS
30 # include <stdlib.h>
31 #else
32 # ifdef HAVE_MALLOC_H
33 #  include <malloc.h>
34 # endif
35 #endif
36 #ifdef HAVE_STRING_H
37 # include <string.h>
38 #else
39 # ifdef HAVE_STRINGS_H
40 #  include <strings.h>
41 # endif
42 #endif
43 #include "compat/strdup.h"
44 #ifdef HAVE_UNISTD_H
45 # include <unistd.h>
46 #endif
47 #include "compat/gethostname.h"
48 #include <errno.h>
49 #include "compat/strerror.h"
50 #include "connection.h"
51 #include "common/bn_type.h"
52 #include "common/queue.h"
53 #include "common/packet.h"
54 #include "common/bot_protocol.h"
55 #include "common/bnet_protocol.h"
56 #include "common/field_sizes.h"
57 #include "common/eventlog.h"
58 #include "common/list.h"
59 #include "common/util.h"
60 #include "common/version.h"
61 #include "common/addr.h"
62 #include "account.h"
63 #include "account_wrap.h"
64 #include "game.h"
65 #include "channel.h"
66 #include "channel_conv.h"
67 #include "command.h"
68 #include "irc.h"
69 #include "message.h"
70 #include "mail.h"
71 #include "prefs.h"
72 #include "common/tag.h"
73 #include "common/xalloc.h"
74 #include "common/setup_after.h"
75 
76 static int message_telnet_format(t_packet * packet, t_message_type type, t_connection * me, t_connection * dst, char const * text, unsigned int dstflags);
77 static int message_bot_format(t_packet * packet, t_message_type type, t_connection * me, t_connection * dst, char const * text, unsigned int dstflags);
78 static int message_bnet_format(t_packet * packet, t_message_type type, t_connection * me, t_connection * dst, char const * text, unsigned int dstflags);
79 static t_packet * message_cache_lookup(t_message * message, t_connection *dst, unsigned int flags);
80 
message_type_get_str(t_message_type type)81 static char const * message_type_get_str(t_message_type type)
82 {
83     switch (type)
84     {
85     case message_type_adduser:
86         return "adduser";
87     case message_type_join:
88         return "join";
89     case message_type_part:
90         return "part";
91     case message_type_whisper:
92         return "whisper";
93     case message_type_talk:
94         return "talk";
95     case message_type_broadcast:
96         return "broadcast";
97     case message_type_channel:
98         return "channel";
99     case message_type_userflags:
100         return "userflags";
101     case message_type_whisperack:
102         return "whisperack";
103     case message_type_friendwhisperack:  //[zap-zero] 20020518
104         return "friendwhisperack";
105     case message_type_channelfull:
106         return "channelfull";
107     case message_type_channeldoesnotexist:
108         return "channeldoesnotexist";
109     case message_type_channelrestricted:
110         return "channelrestricted";
111     case message_type_info:
112         return "info";
113     case message_type_error:
114         return "error";
115     case message_type_emote:
116         return "emote";
117     case message_type_uniqueid:
118         return "uniqueid";
119     case message_type_mode:
120 	return "mode";
121     case message_type_notice:
122         return "notice";
123     case message_type_null:
124         return "null";
125     default:
126         return "UNKNOWN";
127     }
128 }
129 
130 
131 /* make sure none of the expanded format symbols is longer than this (with null) */
132 #define MAX_INC 64
133 
message_format_line(t_connection const * c,char const * in)134 extern char * message_format_line(t_connection const * c, char const * in)
135 {
136     char *       out;
137     unsigned int inpos;
138     unsigned int outpos;
139     unsigned int outlen=MAX_INC;
140     unsigned int inlen;
141     char         clienttag_str[5];
142 
143     out = xmalloc(outlen+1);
144 
145     inlen = strlen(in);
146     out[0] = 'I';
147     for (inpos=0,outpos=1; inpos<inlen; inpos++)
148     {
149         if (in[inpos]!='%')
150 	{
151 	    out[outpos] = in[inpos];
152 	    outpos += 1;
153 	}
154         else
155 	    switch (in[++inpos])
156 	    {
157 	    case '%':
158 		out[outpos++] = '%';
159 		break;
160 
161 	    case 'a':
162 		sprintf(&out[outpos],"%u",accountlist_get_length());
163 		outpos += strlen(&out[outpos]);
164 		break;
165 
166 	    case 'c':
167 		sprintf(&out[outpos],"%d",channellist_get_length());
168 		outpos += strlen(&out[outpos]);
169 		break;
170 
171 	    case 'g':
172 		sprintf(&out[outpos],"%d",gamelist_get_length());
173 		outpos += strlen(&out[outpos]);
174 		break;
175 
176 	    case 'h':
177     		if (gethostname(&out[outpos],MAX_INC)<0)
178     		{
179 		    eventlog(eventlog_level_error,__FUNCTION__,"could not get hostname (gethostname: %s)",pstrerror(errno));
180 		    strcpy(&out[outpos],"localhost"); /* not much else you can do */
181     		}
182 		outpos += strlen(&out[outpos]);
183 		break;
184 
185 	    case 'i':
186 		sprintf(&out[outpos],UID_FORMAT,conn_get_userid(c));
187 		outpos += strlen(&out[outpos]);
188 		break;
189 
190 	    case 'l':
191 	        {
192 		    char const * tname;
193 
194 		    strncpy(&out[outpos],(tname = (conn_get_chatname(c)?conn_get_chatname(c):conn_get_loggeduser(c))),USER_NAME_MAX-1);
195 		    conn_unget_chatname(c,tname);
196 		}
197 		out[outpos+USER_NAME_MAX-1] = '\0';
198 		outpos += strlen(&out[outpos]);
199 		break;
200 
201             case 'm':
202 	    	sprintf(&out[outpos],"%s",check_mail(c));
203 		outpos += strlen(&out[outpos]);
204                 break;
205 
206 	    case 'r':
207 		strncpy(&out[outpos],addr_num_to_ip_str(conn_get_addr(c)),MAX_INC-1);
208 		out[outpos+MAX_INC-1] = '\0';
209 		outpos += strlen(&out[outpos]);
210 		break;
211 
212 	    case 's':
213 		sprintf(&out[outpos],"%s",prefs_get_servername());
214 		outpos += strlen(&out[outpos]);
215 		break;
216 
217 	    case 't':
218 		sprintf(&out[outpos],"%s",tag_uint_to_str(clienttag_str,conn_get_clienttag(c)));
219 		outpos += strlen(&out[outpos]);
220 		break;
221 
222 	    case 'u':
223 		sprintf(&out[outpos],"%d",connlist_login_get_length());
224 		outpos += strlen(&out[outpos]);
225 		break;
226 
227 	    case 'v':
228 		strcpy(&out[outpos],PVPGN_SOFTWARE" "PVPGN_VERSION);
229 		outpos += strlen(&out[outpos]);
230 		break;
231 
232 	    case 'C': /* simulated command */
233 		out[0] = 'C';
234 		break;
235 
236 	    case 'B': /* BROADCAST */
237 		out[0] = 'B';
238 		break;
239 
240 	    case 'E': /* ERROR */
241 		out[0] = 'E';
242 		break;
243 
244 	    case 'G':
245 	    	sprintf(&out[outpos],"%d",game_get_count_by_clienttag(conn_get_clienttag(c)));
246 		outpos += strlen(&out[outpos]);
247 		break;
248 
249 	    case 'H':
250 		strcpy(&out[outpos],prefs_get_contact_name());
251 		outpos += strlen(&out[outpos]);
252 		break;
253 
254 	    case 'I': /* INFO */
255 		out[0] = 'I';
256 		break;
257 
258 	    case 'M': /* MESSAGE */
259 		out[0] = 'M';
260 		break;
261 
262 	    case 'N':
263 	    	strcpy(&out[outpos],clienttag_get_title(conn_get_clienttag(c)));
264 		outpos += strlen(&out[outpos]);
265 		break;
266 
267 	    case 'T': /* EMOTE */
268 		out[0] = 'T';
269 		break;
270 
271 	    case 'U':
272 	    	sprintf(&out[outpos],"%d",conn_get_user_count_by_clienttag(conn_get_clienttag(c)));
273 		outpos += strlen(&out[outpos]);
274 		break;
275 
276 	    case 'W': /* INFO */
277 		out[0] = 'W';
278 		break;
279 
280 	    default:
281 		eventlog(eventlog_level_warn,__FUNCTION__,"bad formatter \"%%%c\"",in[inpos-1]);
282 	    }
283 
284 	if ((outpos+MAX_INC)>=outlen)
285 	{
286 	    char * newout;
287 
288 	    outlen += MAX_INC;
289 	    newout = xrealloc(out,outlen);
290 	    out = newout;
291 	}
292     }
293     out[outpos] = '\0';
294 
295     return out;
296 }
297 
298 
message_telnet_format(t_packet * packet,t_message_type type,t_connection * me,t_connection * dst,char const * text,unsigned int dstflags)299 static int message_telnet_format(t_packet * packet, t_message_type type, t_connection * me, t_connection * dst, char const * text, unsigned int dstflags)
300 {
301     char * msgtemp;
302 
303     if (!packet)
304     {
305 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
306 	return -1;
307     }
308 
309     switch (type)
310     {
311     case message_type_uniqueid:
312 	if (!text)
313 	{
314 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
315 	    return -1;
316 	}
317 	msgtemp = xmalloc(strlen(text)+32);
318         sprintf(msgtemp,"Your unique name: %s\r\n",text);
319 	break;
320     case message_type_adduser:
321 	if (!me)
322 	{
323 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
324 	    return -1;
325 	}
326 	{
327 	    char const * tname;
328 
329 	    tname = conn_get_chatcharname(me, dst);
330 	    msgtemp = xmalloc(strlen(tname)+32);
331 	    sprintf(msgtemp,"[%s is here]\r\n",tname);
332 	    conn_unget_chatcharname(me,tname);
333 	}
334 	break;
335     case message_type_join:
336 	if (!me)
337 	{
338 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
339 	    return -1;
340 	}
341 	{
342 	    char const * tname;
343 
344 	    tname = conn_get_chatcharname(me, dst);
345 	    msgtemp = xmalloc(strlen(tname)+32);
346 	    sprintf(msgtemp,"[%s enters]\r\n",tname);
347 	    conn_unget_chatcharname(me,tname);
348 	}
349 	break;
350     case message_type_part:
351 	if (!me)
352 	{
353 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
354 	    return -1;
355 	}
356 	{
357 	    char const * tname;
358 
359 	    tname = conn_get_chatcharname(me, dst);
360 	    msgtemp = xmalloc(strlen(tname)+32);
361 	    sprintf(msgtemp,"[%s leaves]\r\n",tname);
362 	    conn_unget_chatcharname(me,tname);
363 	}
364 	break;
365     case message_type_whisper:
366     case message_type_notice:
367 	if (!text)
368 	{
369 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
370 	    return -1;
371 	}
372 	if (dstflags&MF_X)
373 	    return -1; /* player is ignored */
374 	{
375 	    char const * tname;
376 	    char const * newtext;
377 
378 	    if (me)
379 		tname = conn_get_chatcharname(me, dst);
380 	    else
381 		tname = prefs_get_servername();
382 
383 	    if ((newtext = escape_chars(text,strlen(text))))
384 	    {
385 		msgtemp = xmalloc(strlen(tname)+8+strlen(newtext)+4);
386 		sprintf(msgtemp,"<from %s> %s\r\n",tname,newtext);
387 		xfree((void *)newtext); /* avoid warning */
388 	    }
389 	    else
390 	    {
391 		msgtemp = xmalloc(16+strlen(tname));
392 		sprintf(msgtemp,"<from %s> \r\n",tname);
393 	    }
394 	    if (me)
395 	        conn_unget_chatcharname(me,tname);
396 	}
397 	break;
398     case message_type_talk:
399 	if (!text)
400 	{
401 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
402 	    return -1;
403 	}
404 	if (dstflags&MF_X)
405 	    return -1; /* player is ignored */
406 	{
407 	    char const * tname;
408 	    char const * newtext;
409 
410 	    if (me)
411 	        tname = conn_get_chatcharname(me, dst);
412 	    else
413 		tname = prefs_get_servername();
414 
415 	    if ((newtext = escape_chars(text,strlen(text))))
416 	    {
417 		msgtemp = xmalloc(strlen(tname)+4+strlen(newtext)+4);
418 		sprintf(msgtemp,"<%s> %s\r\n",tname,newtext);
419 		xfree((void *)newtext); /* avoid warning */
420 	    }
421 	    else
422 	    {
423 		msgtemp = xmalloc(strlen(tname)+8);
424 		sprintf(msgtemp,"<%s> \r\n",tname);
425 	    }
426 	    if (me)
427 	        conn_unget_chatcharname(me,tname);
428 	}
429 	break;
430     case message_type_broadcast:
431 	if (!text)
432 	{
433 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
434 	    return -1;
435 	}
436 	if (dstflags&MF_X)
437 	    return -1; /* player is ignored */
438 	{
439 	    char const * newtext;
440 
441 	    if ((newtext = escape_chars(text,strlen(text))))
442 	    {
443 		msgtemp = xmalloc(16+strlen(newtext)+4);
444 		sprintf(msgtemp,"Broadcast: %s\r\n",newtext); /* FIXME: show source? */
445 		xfree((void *)newtext); /* avoid warning */
446 	    }
447 	    else
448 	    {
449 		msgtemp = xmalloc(16);
450 		sprintf(msgtemp,"Broadcast: \r\n"); /* FIXME: show source? */
451 	    }
452 	}
453 	break;
454     case message_type_channel:
455 	if (!text)
456 	{
457 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
458 	    return -1;
459 	}
460 	msgtemp = xmalloc(strlen(text)+32);
461 	sprintf(msgtemp,"Joining channel: \"%s\"\r\n",text);
462 	break;
463     case message_type_userflags:
464 	if (!me)
465 	{
466 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
467 	    return -1;
468 	}
469 	msgtemp = xstrdup("");
470 	break;
471     case message_type_whisperack:
472 	if (!me)
473 	{
474 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
475 	    return -1;
476 	}
477 	if (!text)
478 	{
479 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
480 	    return -1;
481 	}
482 	{
483 	    char const * tname;
484 	    char const * newtext;
485 
486 	    tname = conn_get_chatcharname(me, dst);
487 	    if ((newtext = escape_chars(text,strlen(text))))
488 	    {
489 		msgtemp = xmalloc(strlen(tname)+8+strlen(newtext)+4);
490 		sprintf(msgtemp,"<to %s> %s\r\n",tname,newtext);
491 		xfree((void *)newtext); /* avoid warning */
492 	    }
493 	    else
494 	    {
495 		msgtemp = xmalloc(strlen(tname)+8+strlen(text)+4);
496 		sprintf(msgtemp,"<to %s> %s\r\n",tname,text);
497 	    }
498 	    conn_unget_chatcharname(me,tname);
499 	}
500 	break;
501     case message_type_friendwhisperack:   // [zap-zero] 20020518
502 	if (!me)
503 	{
504 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
505 	    return -1;
506 	}
507 	if (!text)
508 	{
509 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
510 	    return -1;
511 	}
512 	{
513 	    char const * newtext;
514 
515 	    if ((newtext = escape_chars(text,strlen(text))))
516 	    {
517 		msgtemp = xmalloc(14+8+strlen(newtext)+4);
518 		sprintf(msgtemp,"<to your friends> %s\r\n",newtext);
519 		xfree((void *)newtext); /* avoid warning */
520 	    }
521 	    else
522 	    {
523 		msgtemp = xmalloc(14+8+strlen(text)+4);
524 		sprintf(msgtemp,"<to your friends> %s\r\n",text);
525 	    }
526 	}
527 	break;
528 
529     case message_type_channelfull:
530 	/* FIXME */
531 	msgtemp = xstrdup("");
532 	break;
533     case message_type_channeldoesnotexist:
534 	/* FIXME */
535 	msgtemp = xstrdup("");
536 	break;
537     case message_type_channelrestricted:
538 	/* FIXME */
539 	msgtemp = xstrdup("");
540 	break;
541     case message_type_info:
542 	if (!text)
543 	{
544 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
545 	    return -1;
546 	}
547 	{
548 	    char const * newtext;
549 
550 	    if ((newtext = escape_chars(text,strlen(text))))
551 	    {
552 		msgtemp = xmalloc(strlen(newtext)+4);
553 		sprintf(msgtemp,"%s\r\n",newtext);
554 		xfree((void *)newtext); /* avoid warning */
555 	    }
556 	    else
557 	    {
558 		msgtemp = xmalloc(strlen(text)+4);
559 		sprintf(msgtemp,"%s\r\n",text);
560 	    }
561 	}
562 	break;
563     case message_type_error:
564 	if (!text)
565 	{
566 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
567 	    return -1;
568 	}
569 	{
570 	    char const * newtext;
571 
572 	    if ((newtext = escape_chars(text,strlen(text))))
573 	    {
574 		msgtemp = xmalloc(8+strlen(newtext)+4);
575 		sprintf(msgtemp,"ERROR: %s\r\n",newtext);
576 		xfree((void *)newtext); /* avoid warning */
577 	    }
578 	    else
579 	    {
580 		msgtemp = xmalloc(8+strlen(text)+4);
581 		sprintf(msgtemp,"ERROR: %s\r\n",text);
582 	    }
583 	}
584 	break;
585     case message_type_emote:
586 	if (!me)
587 	{
588 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
589 	    return -1;
590 	}
591 	if (!text)
592 	{
593 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
594 	    return -1;
595 	}
596 	if (dstflags&MF_X)
597 	    return -1; /* player is ignored */
598 	{
599 	    char const * tname;
600 	    char const * newtext;
601 
602 	    tname = conn_get_chatcharname(me, dst);
603 	    if ((newtext = escape_chars(text,strlen(text))))
604 	    {
605 		msgtemp = xmalloc(strlen(tname)+4+strlen(newtext)+4);
606 		sprintf(msgtemp,"<%s %s>\r\n",tname,newtext);
607 		xfree((void *)newtext); /* avoid warning */
608 	    }
609 	    else
610 	    {
611 		msgtemp = xmalloc(strlen(tname)+4+strlen(text)+4);
612 		sprintf(msgtemp,"<%s %s>\r\n",tname,text);
613 	    }
614 	    conn_unget_chatcharname(me,tname);
615 	}
616 	break;
617     case message_type_mode:
618 	if (!me)
619 	{
620 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
621 	    return -1;
622 	}
623 	{
624 	    char const * tname;
625 
626 	    tname = conn_get_chatcharname(me,dst);
627 	    msgtemp = xmalloc(strlen(tname)+32);
628 	    sprintf(msgtemp,"%s change mode: %s\r\n",tname,text);
629 	    conn_unget_chatcharname(me,tname);
630 	}
631     default:
632 	eventlog(eventlog_level_error,__FUNCTION__,"got bad message type %d",(int)type);
633 	return -1;
634     }
635 
636     {
637 	int retval;
638 
639 	retval = packet_append_ntstring(packet,msgtemp);
640 	xfree(msgtemp);
641 	return retval;
642     }
643 }
644 
645 
message_bot_format(t_packet * packet,t_message_type type,t_connection * me,t_connection * dst,char const * text,unsigned int dstflags)646 static int message_bot_format(t_packet * packet, t_message_type type, t_connection * me, t_connection * dst, char const * text, unsigned int dstflags)
647 {
648     char * msgtemp;
649     char clienttag_str[5];
650 
651     if (!packet)
652     {
653 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
654 	return -1;
655     }
656 
657     /* special-case the login banner so it doesn't have numbers
658      * at the start of each line
659      */
660     if (me &&
661         conn_get_state(me)!=conn_state_loggedin &&
662         conn_get_state(me)!=conn_state_destroy &&
663         type!=message_type_null) /* this does not apply for NULL messages */
664     {
665 	if (!text)
666         {
667 #if 0
668 	    /* battle.net actually sends them during login */
669 	    if (type==message_type_null)
670 	    	return 0; /* don't display null messages during the login */
671 #endif
672             eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for non-loggedin state");
673             return -1;
674         }
675 	msgtemp = xmalloc(strlen(text)+4);
676         sprintf(msgtemp,"%s\r\n",text);
677     }
678     else
679 	switch (type)
680 	{
681 	case message_type_null:
682 	    msgtemp = xmalloc(32);
683 	    sprintf(msgtemp,"%u %s\r\n",EID_NULL,"NULL");
684 	    break;
685 	case message_type_uniqueid: /* FIXME: need to send this for some bots, also needed to support guest accounts */
686 	    if (!text)
687 	    {
688 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
689 		return -1;
690 	    }
691 	    msgtemp = xmalloc(strlen(text)+32);
692 	    sprintf(msgtemp,"%u %s %s\r\n",EID_UNIQUENAME,"NAME",text);
693 	    break;
694 	case message_type_adduser:
695 	    if (!me)
696 	    {
697 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
698 		return -1;
699 	    }
700 	    {
701 		char const * tname;
702 
703 		tname = conn_get_chatcharname(me, dst);
704 		msgtemp = xmalloc(32+strlen(tname)+32);
705 		sprintf(msgtemp,"%u %s %s %04x [%s]\r\n",EID_SHOWUSER,"USER",tname,conn_get_flags(me)|dstflags,tag_uint_to_str(clienttag_str,conn_get_fake_clienttag(me)));
706 		conn_unget_chatcharname(me,tname);
707 	    }
708 	    break;
709 	case message_type_join:
710 	    if (!me)
711 	    {
712 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
713 		return -1;
714 	    }
715 	    {
716 		char const * tname;
717 
718 		tname = conn_get_chatcharname(me, dst);
719 		msgtemp = xmalloc(32+strlen(tname)+32);
720 		sprintf(msgtemp,"%u %s %s %04x [%s]\r\n",EID_JOIN,"JOIN",tname,conn_get_flags(me)|dstflags,tag_uint_to_str(clienttag_str,conn_get_fake_clienttag(me)));
721 		conn_unget_chatcharname(me,tname);
722 	    }
723 	    break;
724 	case message_type_part:
725 	    if (!me)
726 	    {
727 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
728 		return -1;
729 	    }
730 	    {
731 		char const * tname;
732 
733 		tname = conn_get_chatcharname(me, dst);
734 		msgtemp = xmalloc(32+strlen(tname)+32);
735 		sprintf(msgtemp,"%u %s %s %04x\r\n",EID_LEAVE,"LEAVE",tname,conn_get_flags(me)|dstflags);
736 		conn_unget_chatcharname(me,tname);
737 	    }
738 	    break;
739 	case message_type_whisper:
740 	case message_type_notice:
741 	    if (!text)
742 	    {
743 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
744 		return -1;
745 	    }
746 	    if (dstflags&MF_X)
747 		return -1; /* player is ignored */
748 	    {
749 		char const * tname;
750 
751 		if (me)
752 		    tname = conn_get_chatcharname(me, dst);
753 		else
754 		    tname = prefs_get_servername();
755 
756 		msgtemp = xmalloc(32+strlen(tname)+32+strlen(text));
757 		sprintf(msgtemp,"%u %s %s %04x \"%s\"\r\n",EID_WHISPER,"WHISPER",tname,me?conn_get_flags(me)|dstflags:dstflags,text);
758 		if (me)
759 		    conn_unget_chatcharname(me,tname);
760 	    }
761 	    break;
762 	case message_type_talk:
763 	    if (!me)
764 	    {
765 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
766 		return -1;
767 	    }
768 	    if (!text)
769 	    {
770 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
771 		return -1;
772 	    }
773 	    if (dstflags&MF_X)
774 		return -1; /* player is ignored */
775 	    {
776 		char const * tname;
777 
778 		tname = conn_get_chatcharname(me, dst);
779 		msgtemp = xmalloc(32+strlen(tname)+32+strlen(text));
780 		sprintf(msgtemp,"%u %s %s %04x \"%s\"\r\n",EID_TALK,"TALK",tname,conn_get_flags(me)|dstflags,text);
781 		conn_unget_chatcharname(me,tname);
782 	    }
783 	    break;
784 	case message_type_broadcast:
785 	    if (!text)
786 	    {
787 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
788 		return -1;
789 	    }
790 	    if (dstflags&MF_X)
791 		return -1; /* player is ignored */
792 	    msgtemp = xmalloc(32+32+strlen(text));
793 	    sprintf(msgtemp,"%u %s \"%s\"\r\n",EID_BROADCAST,"_",text); /* FIXME: what does this look like on Battle.net? */
794 	    break;
795 	case message_type_channel:
796 	    if (!text)
797 	    {
798 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
799 		return -1;
800 	    }
801 	    msgtemp = xmalloc(32+strlen(text));
802 	    sprintf(msgtemp,"%u %s \"%s\"\r\n",EID_CHANNEL,"CHANNEL",text);
803 	    break;
804 	case message_type_userflags:
805 	    if (!me)
806 	    {
807 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
808 		return -1;
809 	    }
810 	    {
811 		char const * tname;
812 
813 		tname = conn_get_chatcharname(me, dst);
814 		msgtemp = xmalloc(32+strlen(tname)+16);
815 		sprintf(msgtemp,"%u %s %s %04x\r\n",EID_USERFLAGS,"USER",tname,conn_get_flags(me)|dstflags);
816 		conn_unget_chatcharname(me,tname);
817 	    }
818 	    break;
819 	case message_type_whisperack:
820 	    if (!me)
821 	    {
822 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
823 		return -1;
824 	    }
825 	    if (!text)
826 	    {
827 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
828 		return -1;
829 	    }
830 	    {
831 		char const * tname;
832 
833 		tname = conn_get_chatcharname(me, dst);
834 		msgtemp = xmalloc(32+strlen(tname)+32+strlen(text));
835 		sprintf(msgtemp,"%u %s %s %04x \"%s\"\r\n",EID_WHISPERSENT,"WHISPER",tname,conn_get_flags(me)|dstflags,text);
836 		conn_unget_chatcharname(me,tname);
837 	    }
838 	    break;
839 	case message_type_friendwhisperack: // [zap-zero] 20020518
840 	    if (!me)
841 	    {
842 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
843 		return -1;
844 	    }
845 	    if (!text)
846 	    {
847 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
848 		return -1;
849 	    }
850 	    {
851 		msgtemp = xmalloc(32+16+32+strlen(text));
852 		sprintf(msgtemp,"%u %s \"your friends\" %04x \"%s\"\r\n",EID_WHISPERSENT,"WHISPER",conn_get_flags(me)|dstflags,text);
853 	    }
854 	    break;
855 
856 	case message_type_channelfull:
857 	    msgtemp = xmalloc(32);
858 	    sprintf(msgtemp,"%u \r\n",EID_CHANNELFULL); /* FIXME */
859 	    break;
860 	case message_type_channeldoesnotexist:
861 	    msgtemp = xmalloc(32);
862 	    sprintf(msgtemp,"%u \r\n",EID_CHANNELDOESNOTEXIST); /* FIXME */
863 	    break;
864 	case message_type_channelrestricted:
865 	    msgtemp = xmalloc(32);
866 	    sprintf(msgtemp,"%u \r\n",EID_CHANNELRESTRICTED); /* FIXME */
867 	    break;
868 	case message_type_info:
869 	    if (!text)
870 	    {
871 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
872 		return -1;
873 	    }
874 	    msgtemp = xmalloc(32+16+strlen(text));
875 	    sprintf(msgtemp,"%u %s \"%s\"\r\n",EID_INFO,"INFO",text);
876 	    break;
877 	case message_type_error:
878 	    if (!text)
879 	    {
880 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
881 		return -1;
882 	    }
883 	    msgtemp = xmalloc(32+16+strlen(text));
884 	    sprintf(msgtemp,"%u %s \"%s\"\r\n",EID_ERROR,"ERROR",text);
885 	    break;
886 	case message_type_emote:
887 	    if (!me)
888 	    {
889 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
890 		return -1;
891 	    }
892 	    if (!text)
893 	    {
894 		eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
895 		return -1;
896 	    }
897 	    if (dstflags&MF_X)
898 		return -1; /* player is ignored */
899 	    {
900 		char const * tname;
901 
902 		tname = conn_get_chatcharname(me, dst);
903 		msgtemp = xmalloc(32+strlen(tname)+32+strlen(text));
904 		sprintf(msgtemp,"%u %s %s %04x \"%s\"\r\n",EID_EMOTE,"EMOTE",tname,conn_get_flags(me)|dstflags,text);
905 		conn_unget_chatcharname(me,tname);
906 	    }
907 	    break;
908 	default:
909 	    eventlog(eventlog_level_error,__FUNCTION__,"got bad message type %d",(int)type);
910 	    return -1;
911 	}
912 
913     if (strlen(msgtemp)>MAX_MESSAGE_LEN)
914 	msgtemp[MAX_MESSAGE_LEN] = '\0'; /* now truncate to max size */
915 
916     {
917 	int retval;
918 
919 	retval = packet_append_ntstring(packet,msgtemp);
920 	xfree(msgtemp);
921 	return retval;
922     }
923 }
924 
925 
message_bnet_format(t_packet * packet,t_message_type type,t_connection * me,t_connection * dst,char const * text,unsigned int dstflags)926 static int message_bnet_format(t_packet * packet, t_message_type type, t_connection * me, t_connection * dst, char const * text, unsigned int dstflags)
927 {
928     if (!packet)
929     {
930 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
931 	return -1;
932     }
933 
934     if (text && text[0]=='\0')
935         text = " "; /* empty messages crash some clients, just send whitespace */
936 
937     packet_set_size(packet,sizeof(t_server_message));
938     packet_set_type(packet,SERVER_MESSAGE);
939     bn_int_set(&packet->u.server_message.player_ip,SERVER_MESSAGE_PLAYER_IP_DUMMY);
940     bn_int_nset(&packet->u.server_message.account_num,SERVER_MESSAGE_ACCOUNT_NUM);
941     bn_int_set(&packet->u.server_message.reg_auth,SERVER_MESSAGE_REG_AUTH);
942 
943     switch (type)
944     {
945     case message_type_adduser:
946 	if (!me)
947 	{
948 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
949 	    return -1;
950 	}
951         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_ADDUSER);
952 		bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags);
953 		bn_int_set(&packet->u.server_message.latency,conn_get_latency(me));
954 	{
955 	    char const * tname;
956 	    char const * playerinfo;
957 
958 	    tname = conn_get_chatcharname(me, dst);
959 	    packet_append_string(packet,tname);
960 	    conn_unget_chatcharname(me,tname);
961 	    if ((conn_get_clienttag(me) == CLIENTTAG_WARCRAFT3_UINT) || (conn_get_clienttag(me) == CLIENTTAG_WAR3XP_UINT))
962 		playerinfo = conn_get_w3_playerinfo(me);
963 	    else playerinfo = conn_get_playerinfo(me);
964 
965 	    if (playerinfo == NULL) { playerinfo = ""; }
966 	    packet_append_string(packet,playerinfo);
967 	}
968 	break;
969     case message_type_join:
970 	if (!me)
971 	{
972 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
973 	    return -1;
974 	}
975         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_JOIN);
976 	bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags);
977 	bn_int_set(&packet->u.server_message.latency,conn_get_latency(me));
978 	{
979 	    char const * tname;
980 	    char const * playerinfo;
981 
982 	    tname = conn_get_chatcharname(me, dst);
983 	    packet_append_string(packet,tname);
984 	    conn_unget_chatcharname(me,tname);
985 
986 	    if ((conn_get_clienttag(me) == CLIENTTAG_WARCRAFT3_UINT) || (conn_get_clienttag(me) == CLIENTTAG_WAR3XP_UINT))
987 		playerinfo = conn_get_w3_playerinfo(me);
988 	    else playerinfo = conn_get_playerinfo(me);
989 
990 	    if (playerinfo == NULL) { playerinfo = ""; }
991 	    packet_append_string(packet, playerinfo);
992 	}
993 	break;
994     case message_type_part:
995 	if (!me)
996 	{
997 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
998 	    return -1;
999 	}
1000         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_PART);
1001 	bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags);
1002 	bn_int_set(&packet->u.server_message.latency,conn_get_latency(me));
1003 	{
1004 	    char const * tname;
1005 
1006 	    tname = conn_get_chatcharname(me, dst);
1007 	    packet_append_string(packet,tname);
1008 	    conn_unget_chatcharname(me,tname);
1009 	    packet_append_string(packet,"");
1010 	}
1011 	break;
1012     case message_type_whisper:
1013     case message_type_notice:
1014 	if (!text)
1015 	{
1016 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
1017 	    return -1;
1018 	}
1019 	if (dstflags&MF_X)
1020 	    return -1; /* player is ignored */
1021         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_WHISPER);
1022 	bn_int_set(&packet->u.server_message.flags,me?conn_get_flags(me)|dstflags:dstflags);
1023 	bn_int_set(&packet->u.server_message.latency,me?conn_get_latency(me):0);
1024 
1025 	if (me)
1026 	{
1027 	    char const * tname;
1028 
1029 	    tname = conn_get_chatcharname(me, dst);
1030 	    packet_append_string(packet,tname);
1031 	    conn_unget_chatcharname(me,tname);
1032 	}
1033 	else
1034 	packet_append_string(packet,prefs_get_servername());
1035 
1036         packet_append_string(packet,text);
1037 
1038 	break;
1039     case message_type_talk:
1040 	if (!me)
1041 	{
1042 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
1043 	    return -1;
1044 	}
1045 	if (!text)
1046 	{
1047 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
1048 	    return -1;
1049 	}
1050 	if (dstflags&MF_X)
1051 	    return -1; /* player is ignored */
1052         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_TALK);
1053 	bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags);
1054 	bn_int_set(&packet->u.server_message.latency,conn_get_latency(me));
1055 	{
1056 	    char const * tname;
1057 
1058 	    tname = conn_get_chatcharname(me, dst);
1059 	    packet_append_string(packet,tname);
1060 	    conn_unget_chatcharname(me,tname);
1061 	    packet_append_string(packet,text);
1062 	}
1063 	break;
1064     case message_type_broadcast:
1065 	if (!text)
1066 	{
1067 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
1068 	    return -1;
1069 	}
1070 	if (dstflags&MF_X)
1071 	    return -1; /* player is ignored */
1072         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_BROADCAST);
1073 	bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags);
1074 	bn_int_set(&packet->u.server_message.latency,conn_get_latency(me));
1075 	{
1076 	    char const * tname;
1077 
1078 	    tname = conn_get_chatcharname(me, dst);
1079 	    packet_append_string(packet,tname);
1080 	    conn_unget_chatcharname(me,tname);
1081 	    packet_append_string(packet,text);
1082 	}
1083 	break;
1084     case message_type_channel:
1085 	if (!me)
1086 	{
1087 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
1088 	    return -1;
1089 	}
1090 	if (!text)
1091 	{
1092 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
1093 	    return -1;
1094 	}
1095         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_CHANNEL);
1096 	{
1097 	    t_channel const * channel;
1098 
1099 	    if (!(channel = conn_get_channel(me)))
1100 		bn_int_set(&packet->u.server_message.flags,0);
1101 	    else
1102 		bn_int_set(&packet->u.server_message.flags,cflags_to_bncflags(channel_get_flags(channel)));
1103 	}
1104 	bn_int_set(&packet->u.server_message.latency,conn_get_latency(me));
1105 	{
1106 	    char const * tname;
1107 
1108 	    tname = conn_get_chatname(me);
1109 	    packet_append_string(packet,tname);
1110 	    conn_unget_chatname(me,tname);
1111 	    packet_append_string(packet,text);
1112 	}
1113 	break;
1114     case message_type_userflags:
1115 	if (!me)
1116 	{
1117 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
1118 	    return -1;
1119 	}
1120         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_USERFLAGS);
1121 		bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags);
1122 		bn_int_set(&packet->u.server_message.latency,conn_get_latency(me));
1123 	{
1124 	    char const * tname;
1125 	    char const * playerinfo;
1126 
1127 	    tname = conn_get_chatcharname(me, dst);
1128 	    packet_append_string(packet,tname);
1129 	    conn_unget_chatcharname(me,tname);
1130 	    if ((conn_get_clienttag(me) == CLIENTTAG_WARCRAFT3_UINT) || (conn_get_clienttag(me) == CLIENTTAG_WAR3XP_UINT))
1131 		playerinfo = conn_get_w3_playerinfo(me);
1132 	    else playerinfo = conn_get_playerinfo(me);
1133 
1134 	    if (playerinfo == NULL) { playerinfo = ""; }
1135 
1136 	    packet_append_string(packet, playerinfo);
1137 	}
1138 	break;
1139     case message_type_whisperack:
1140 	if (!me)
1141 	{
1142 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
1143 	    return -1;
1144 	}
1145 	if (!text)
1146 	{
1147 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
1148 	    return -1;
1149 	}
1150         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_WHISPERACK);
1151 	bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags);
1152 	bn_int_set(&packet->u.server_message.latency,conn_get_latency(me));
1153 	{
1154 	    char const * tname;
1155 
1156 	    tname = conn_get_chatcharname(me, dst);
1157 	    packet_append_string(packet,tname);
1158 	    conn_unget_chatcharname(me,tname);
1159 	    packet_append_string(packet,text);
1160 	}
1161 	break;
1162     case message_type_friendwhisperack:  // [zap-zero] 20020518
1163 	if (!me)
1164 	{
1165 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
1166 	    return -1;
1167 	}
1168 	if (!text)
1169 	{
1170 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
1171 	    return -1;
1172 	}
1173         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_WHISPERACK);
1174 	bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags);
1175 	bn_int_set(&packet->u.server_message.latency,conn_get_latency(me));
1176 	{
1177 
1178 	    packet_append_string(packet,"your friends");
1179 	    packet_append_string(packet,text);
1180 	}
1181 	break;
1182 
1183     case message_type_channelfull: /* FIXME */
1184         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_CHANNELFULL);
1185 	bn_int_set(&packet->u.server_message.flags,0);
1186 	bn_int_set(&packet->u.server_message.latency,0);
1187 	packet_append_string(packet,"");
1188 	packet_append_string(packet,"");
1189 	break;
1190     case message_type_channeldoesnotexist:
1191 	if (!me)
1192 	{
1193 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
1194 	    return -1;
1195 	}
1196 	if (!text)
1197 	{
1198 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
1199 	    return -1;
1200 	}
1201         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_CHANNELDOESNOTEXIST);
1202 	bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags);
1203 	bn_int_set(&packet->u.server_message.latency,conn_get_latency(me));
1204 	{
1205 	    char const * tname;
1206 
1207 	    tname = conn_get_chatname(me);
1208 	    packet_append_string(packet,tname);
1209 	    conn_unget_chatname(me,tname);
1210 	    packet_append_string(packet,text);
1211 	}
1212 	break;
1213     case message_type_channelrestricted: /* FIXME */
1214         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_CHANNELRESTRICTED);
1215 	bn_int_set(&packet->u.server_message.flags,0);
1216 	bn_int_set(&packet->u.server_message.latency,0);
1217 	packet_append_string(packet,"");
1218 	packet_append_string(packet,"");
1219 	break;
1220     case message_type_info:
1221 	if (!text)
1222 	{
1223 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
1224 	    return -1;
1225 	}
1226         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_INFO);
1227 	bn_int_set(&packet->u.server_message.flags,0);
1228 	bn_int_set(&packet->u.server_message.latency,0);
1229 	packet_append_string(packet,"");
1230 	packet_append_string(packet,text);
1231 	break;
1232     case message_type_error:
1233 	if (!text)
1234 	{
1235 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
1236 	    return -1;
1237 	}
1238         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_ERROR);
1239 	bn_int_set(&packet->u.server_message.flags,0);
1240 	bn_int_set(&packet->u.server_message.latency,0);
1241 	packet_append_string(packet,"");
1242 	packet_append_string(packet,text);
1243 	break;
1244     case message_type_emote:
1245 	if (!me)
1246 	{
1247 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection for %s",message_type_get_str(type));
1248 	    return -1;
1249 	}
1250 	if (!text)
1251 	{
1252 	    eventlog(eventlog_level_error,__FUNCTION__,"got NULL text for %s",message_type_get_str(type));
1253 	    return -1;
1254 	}
1255 	if (dstflags&MF_X)
1256 	    return -1; /* player is ignored */
1257         bn_int_set(&packet->u.server_message.type,SERVER_MESSAGE_TYPE_EMOTE);
1258 	bn_int_set(&packet->u.server_message.flags,conn_get_flags(me)|dstflags);
1259 	bn_int_set(&packet->u.server_message.latency,conn_get_latency(me));
1260 	{
1261 	    char const * tname;
1262 
1263 	    tname = conn_get_chatcharname(me, dst);
1264 	    packet_append_string(packet,tname);
1265 	    conn_unget_chatcharname(me,tname);
1266 	    packet_append_string(packet,text);
1267 	}
1268 	break;
1269     default:
1270 	eventlog(eventlog_level_error,__FUNCTION__,"got bad message type %d",(int)type);
1271 	return -1;
1272     }
1273 
1274     return 0;
1275 }
1276 
1277 
message_create(t_message_type type,t_connection * src,t_connection * dst,char const * text)1278 extern t_message * message_create(t_message_type type, t_connection * src, t_connection * dst, char const * text)
1279 {
1280     t_message * message;
1281 
1282     message = xmalloc(sizeof(t_message));
1283     message->num_cached = 0;
1284     message->packets    = NULL;
1285     message->classes    = NULL;
1286     message->dstflags   = NULL;
1287     message->mclasses	= NULL;
1288     message->type       = type;
1289     message->src        = src;
1290     message->dst        = dst;
1291     message->text       = text;
1292 
1293     return message;
1294 }
1295 
1296 
message_destroy(t_message * message)1297 extern int message_destroy(t_message * message)
1298 {
1299     unsigned int i;
1300 
1301     if (!message)
1302     {
1303 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL message");
1304 	return -1;
1305     }
1306 
1307     for (i=0; i<message->num_cached; i++)
1308 	if (message->packets[i])
1309 	    packet_del_ref(message->packets[i]);
1310     if (message->packets)
1311 	xfree(message->packets);
1312     if (message->classes)
1313 	xfree(message->classes);
1314     if (message->dstflags)
1315 	xfree(message->dstflags);
1316     if (message->mclasses)
1317 	xfree(message->mclasses);
1318     xfree(message);
1319 
1320     return 0;
1321 }
1322 
1323 
message_cache_lookup(t_message * message,t_connection * dst,unsigned int dstflags)1324 static t_packet * message_cache_lookup(t_message * message, t_connection *dst, unsigned int dstflags)
1325 {
1326     unsigned int i;
1327     t_packet * packet;
1328     t_message_class mclass;
1329     t_conn_class class;
1330 
1331     if (!message)
1332     {
1333 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL message");
1334 	return NULL;
1335     }
1336 
1337     class = conn_get_class(dst);
1338     mclass = conn_get_message_class(message->src, dst);
1339     for (i=0; i<message->num_cached; i++)
1340         if (message->classes[i]==class && message->dstflags[i]==dstflags
1341 	    && message->mclasses[i]==mclass)
1342 	    return message->packets[i];
1343 
1344     {
1345 	t_packet * *   temp_packets;
1346 	t_conn_class * temp_classes;
1347 	unsigned int * temp_dstflags;
1348 	t_message_class *temp_mclasses;
1349 
1350 	if (!message->packets)
1351 	    temp_packets = xmalloc(sizeof(t_packet *)*(message->num_cached+1));
1352 	else
1353 	    temp_packets = xrealloc(message->packets,sizeof(t_packet *)*(message->num_cached+1));
1354 
1355 	if (!message->classes)
1356 	    temp_classes = xmalloc(sizeof(t_conn_class)*(message->num_cached+1));
1357 	else
1358 	    temp_classes = xrealloc(message->classes,sizeof(t_conn_class)*(message->num_cached+1));
1359 
1360 	if (!message->dstflags)
1361 	    temp_dstflags = xmalloc(sizeof(unsigned int)*(message->num_cached+1));
1362 	else
1363 	    temp_dstflags = xrealloc(message->dstflags,sizeof(unsigned int)*(message->num_cached+1));
1364 
1365 	if (!message->mclasses)
1366 	    temp_mclasses = xmalloc(sizeof(t_message_class)*(message->num_cached+1));
1367 	else
1368 	    temp_mclasses = xrealloc(message->mclasses,sizeof(t_message_class)*(message->num_cached+1));
1369 
1370 	message->packets = temp_packets;
1371 	message->classes = temp_classes;
1372 	message->dstflags = temp_dstflags;
1373 	message->mclasses = temp_mclasses;
1374     }
1375 
1376     switch (class)
1377     {
1378     case conn_class_telnet:
1379 	if (!(packet = packet_create(packet_class_raw)))
1380 	{
1381 	    eventlog(eventlog_level_error,__FUNCTION__,"could not create packet");
1382 	    return NULL;
1383 	}
1384 	if (message_telnet_format(packet,message->type,message->src,message->dst,message->text,dstflags)<0)
1385 	{
1386 	    packet_del_ref(packet);
1387 	    packet = NULL; /* we can cache the NULL too */
1388 	}
1389 	break;
1390     case conn_class_bot:
1391 	if (!(packet = packet_create(packet_class_raw)))
1392 	{
1393 	    eventlog(eventlog_level_error,__FUNCTION__,"could not create packet");
1394 	    return NULL;
1395 	}
1396 	if (message_bot_format(packet,message->type,message->src,message->dst,message->text,dstflags)<0)
1397 	{
1398 	    packet_del_ref(packet);
1399 	    packet = NULL; /* we can cache the NULL too */
1400 	}
1401 	break;
1402     case conn_class_bnet:
1403 	if (!(packet = packet_create(packet_class_bnet)))
1404 	{
1405 	    eventlog(eventlog_level_error,__FUNCTION__,"could not create packet");
1406 	    return NULL;
1407 	}
1408 	if (message_bnet_format(packet,message->type,message->src,dst,message->text,dstflags)<0)
1409 	{
1410 	    packet_del_ref(packet);
1411 	    packet = NULL; /* we can cache the NULL too */
1412 	}
1413 	break;
1414      case conn_class_irc:
1415      case conn_class_wol:
1416 	if (!(packet = packet_create(packet_class_raw)))
1417 	{
1418 	    eventlog(eventlog_level_error,__FUNCTION__,"could not create packet");
1419 	    return NULL;
1420 	}
1421 	/* irc_message_format() is in irc.c */
1422 	if (irc_message_format(packet,message->type,message->src,message->dst,message->text,dstflags)<0)
1423 	{
1424 	    packet_del_ref(packet);
1425 	    packet = NULL; /* we can cache the NULL too */
1426 	}
1427 	break;
1428    case conn_class_init:
1429    case conn_class_file:
1430    case conn_class_d2cs_bnetd:
1431    case conn_class_w3route:
1432 	packet = NULL;
1433 	break; /* cache the NULL but dont send any error,
1434 	        * this are normal connections */
1435    default:
1436 	eventlog(eventlog_level_error,__FUNCTION__,"unsupported connection class %d",(int)class);
1437 	packet = NULL; /* we can cache the NULL too */
1438     }
1439 
1440     message->num_cached++;
1441     message->packets[i] = packet;
1442     message->classes[i] = class;
1443     message->dstflags[i] = dstflags;
1444     message->mclasses[i] = mclass;
1445 
1446     return packet;
1447 }
1448 
1449 
message_send(t_message * message,t_connection * dst)1450 extern int message_send(t_message * message, t_connection * dst)
1451 {
1452     t_packet *   packet;
1453     unsigned int dstflags;
1454 
1455     if (!message)
1456     {
1457 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL message");
1458 	return -1;
1459     }
1460     if (!dst)
1461     {
1462 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL dst connection");
1463 	return -1;
1464     }
1465 
1466     dstflags = 0;
1467     if (message->src)
1468     {
1469 	char const * tname;
1470 
1471 	if ((tname = conn_get_chatname(message->src)) && conn_check_ignoring(dst,tname)==1)
1472 	{
1473 	    conn_unget_chatname(message->src,tname);
1474 	    dstflags |= MF_X;
1475 	}
1476 	if (tname)
1477 	    conn_unget_chatname(message->src,tname);
1478     }
1479 
1480     if (!(packet = message_cache_lookup(message,dst,dstflags)))
1481 	return -1;
1482 
1483     /* FIXME: this is not needed now, message has dst */
1484     if ((conn_get_class(dst)==conn_class_irc)||(conn_get_class(dst)==conn_class_wol)) {
1485     	/* HACK: IRC message always need the recipient and are therefore bad to cache. */
1486 	/*       So we only cache a pseudo packet and convert it to a real packet later ... */
1487 	packet = packet_duplicate(packet); /* we want to modify packet so we have to create a copy ... */
1488     	if (irc_message_postformat(packet,dst)<0) {
1489 	    packet_del_ref(packet); /* we don't need the previously created copy anymore ... */
1490     	    return -1;
1491 	}
1492     }
1493 
1494     conn_push_outqueue(dst,packet);
1495 
1496     if ((conn_get_class(dst)==conn_class_irc)||(conn_get_class(dst)==conn_class_wol))
1497     	packet_del_ref(packet); /* we don't need the previously created copy anymore ... */
1498 
1499     return 0;
1500 }
1501 
1502 
message_send_all(t_message * message)1503 extern int message_send_all(t_message * message)
1504 {
1505     t_connection * c;
1506     t_elem const * curr;
1507     int            rez;
1508 
1509     if (!message)
1510     {
1511 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL message");
1512 	return -1;
1513     }
1514 
1515     rez = -1;
1516     LIST_TRAVERSE_CONST(connlist(),curr)
1517     {
1518 	c = elem_get_data(curr);
1519 	if (message_send(message,c)==0)
1520 	    rez = 0;
1521     }
1522 
1523     return rez;
1524 }
1525 
1526 
message_send_text(t_connection * dst,t_message_type type,t_connection * src,char const * text)1527 extern int message_send_text(t_connection * dst, t_message_type type, t_connection * src, char const * text)
1528 {
1529     t_message * message;
1530     int         rez;
1531 
1532     if (!dst)
1533     {
1534 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
1535 	return -1;
1536     }
1537 
1538     if (!(message = message_create(type,src,dst,text)))
1539 	return -1;
1540     rez = message_send(message,dst);
1541     message_destroy(message);
1542 
1543     return rez;
1544 }
1545 
1546 
message_send_admins(t_connection * src,t_message_type type,char const * text)1547 extern int message_send_admins(t_connection * src, t_message_type type, char const * text)
1548 {
1549     t_elem	const * curr;
1550     t_connection *	tc;
1551     int			counter = 0;
1552 
1553     LIST_TRAVERSE_CONST(connlist(),curr)
1554     {
1555 	tc = elem_get_data(curr);
1556 	if (!tc)
1557 	    continue;
1558 	if (account_get_auth_admin(conn_get_account(tc),NULL)==1 && tc != src)
1559 	{
1560 	    message_send_text(tc,type,src,text);
1561 	    counter++;
1562 	}
1563     }
1564 
1565     return counter;
1566 }
1567 
1568 
message_send_formatted(t_connection * dst,char const * text)1569 extern int message_send_formatted(t_connection * dst, char const * text)
1570 {
1571     char * line;
1572 
1573     if (!dst)
1574     {
1575 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
1576 	return -1;
1577     }
1578 
1579     if (!(line = message_format_line(dst,text)))
1580     {
1581 	eventlog(eventlog_level_error,__FUNCTION__,"could not format input text \"%s\"",text);
1582 	return -1;
1583     }
1584 
1585     /* caller beware: empty messages can crash Blizzard clients */
1586     switch (line[0])
1587     {
1588     case 'C':
1589 	if (line[1]=='/')
1590 	    handle_command(dst,&line[1]);
1591 	else
1592             if (conn_get_channel(dst) && !conn_quota_exceeded(dst,&line[1]))
1593                 channel_message_send(conn_get_channel(dst),message_type_talk,dst,&line[1]);
1594 	break;
1595     case 'B':
1596 	message_send_text(dst,message_type_broadcast,dst,&line[1]);
1597 	break;
1598     case 'E':
1599 	message_send_text(dst,message_type_error,dst,&line[1]);
1600 	break;
1601     case 'M':
1602 	message_send_text(dst,message_type_talk,dst,&line[1]);
1603 	break;
1604     case 'T':
1605 	message_send_text(dst,message_type_emote,dst,&line[1]);
1606 	break;
1607     case 'I':
1608     case 'W':
1609 	message_send_text(dst,message_type_info,dst,&line[1]);
1610 	break;
1611     default:
1612 	eventlog(eventlog_level_error,__FUNCTION__,"unknown message type '%c'",line[0]);
1613 	xfree(line);
1614 	return -1;
1615     }
1616 
1617     xfree(line);
1618     return 0;
1619 }
1620 
1621 
message_send_file(t_connection * dst,FILE * fd)1622 extern int message_send_file(t_connection * dst, FILE * fd)
1623 {
1624     char * buff;
1625 
1626     if (!dst)
1627     {
1628 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
1629 	return -1;
1630     }
1631     if (!fd)
1632     {
1633 	eventlog(eventlog_level_error,__FUNCTION__,"got NULL fd");
1634 	return -1;
1635     }
1636 
1637     while ((buff = file_get_line(fd)))
1638     {
1639 	message_send_formatted(dst,buff);
1640     }
1641     file_get_line(NULL); // clear file_get_line buffer
1642 
1643     return 0;
1644 }
1645