1 #define AUTO_VERSION "1.00"
2 
3 /*
4  *
5  * Written by Colten Edwards. (C) Nov 11/99
6  *
7  */
8 
9 #include "irc.h"
10 #include "struct.h"
11 #include "dcc.h"
12 #include "ircaux.h"
13 #include "ctcp.h"
14 #include "cdcc.h"
15 #include "input.h"
16 #include "status.h"
17 #include "lastlog.h"
18 #include "screen.h"
19 #include "vars.h"
20 #include "misc.h"
21 #include "output.h"
22 #include "module.h"
23 #include "hook.h"
24 #include "hash2.h"
25 #include "bsdglob.h"
26 #define INIT_MODULE
27 #include "modval.h"
28 
29 #include <sys/time.h>
30 #include <sys/stat.h>
31 
32 #define cparse convert_output_format
33 #define FS "%PFS%w:%n"
34 
35 #define DEFAULT_IMPRESS_TIME 30
36 #define DEFAULT_FSERV 1
37 #define DEFAULT_IMPRESS 0
38 #define DEFAULT_MAX_MATCH 4
39 #define DEFAULT_RECURSE 1
40 #define DEFAULT_FILEMASK "*.mp3"
41 
42 
43 char fserv_version[] = "Fserv 1.000";
44 char *fserv_filename = NULL;
45 char FSstr[80] = "FS:";
46 
47 typedef struct _Stats {
48 	unsigned long total_files;
49 	unsigned long total_filesize;
50 	unsigned long files_served;
51 	unsigned long filesize_served;
52 	double max_speed;
53 	time_t starttime;
54 } Stats;
55 
56 Stats statistics = { 0, };
57 
58 /*
59  * ideas.
60  * make it notice instead of msg the nick.
61  * make it allow /msg nick !filename
62  */
63 
64 #if 0
65 <Lena-:#mp3jukebox> <><>< For My List(1069 files: 4307MB) and DCC Status Type
66    @Lena- and @Lena--stats [(1/10) Slots Taken (0/10) Ques
67    Taken] [Open Slot Ready] [Bandwidth in Use: 3081cps]
68    [Highest Cps Record: 56.3kb/s by Grey13] [Total Files
69    Served: 6045] ><><>
70 <Gaff> [ !Gaff Is It Too Late Now.mp3 ] [2.6MB 128Kbps 44.1Khz Joint Stereo
71     (2m44s)]-SpR-@Gaff -> request my list-@Gaff-que -> check
72     que-@Gaff-stats -> check DCC stats-@Gaff-remove -> cancel
73     song request
74 #endif
75 
76 typedef struct _AUDIO_HEADER {
77 	int IDex;
78 	int ID;
79 	int layer;
80 	int protection_bit;
81 	int bitrate_index;
82 	int sampling_frequency;
83 	int padding_bit;
84 	int private_bit;
85 	int mode; /* 0 = STEREO 1 = Joint 2 = DUAL 3 = Mono */
86 	int mode_extension;
87 	int copyright;
88 	int original;
89 	int emphasis;
90 	int stereo;
91 	int jsbound;
92 	int sblimit;
93 	int true_layer;
94 	int framesize;
95 } AUDIO_HEADER;
96 
97 
98 static unsigned char _buffer[32];
99 static int _bptr = 0;
100 
101 
102 typedef struct _files {
103 	struct _files	*next;
104 	char		*filename;
105 	unsigned long	filesize;
106 	time_t		time;
107 	int		bitrate;
108 	int		freq;
109 	int		stereo;
110 	int		id3;
111 } Files;
112 
113 Files *fserv_files = NULL;
114 
115 
mode_str(int mode)116 char *mode_str(int mode)
117 {
118 	switch(mode)
119 	{
120 		case 0:
121 			return "Stereo";
122 		case 1:
123 			return "Joint-Stereo";
124 		case 2:
125 			return "Dual-Channel";
126 		case 3:
127 			return "Mono";
128 	}
129 	return empty_string;
130 }
131 
print_time(time_t input)132 char *print_time(time_t input)
133 {
134 	static char	buff[40];
135 	time_t		seconds,
136 			minutes;
137 	seconds = input;
138 	minutes = seconds / 60;
139 	seconds = seconds % 60;
140 	sprintf(buff, "%02u:%02u", (unsigned int)minutes, (unsigned int)seconds);
141 	return buff;
142 }
143 
make_mp3_string(FILE * fp,Files * f,char * fs,char * dirbuff)144 char *make_mp3_string(FILE *fp, Files *f, char *fs, char *dirbuff)
145 {
146 	static char	buffer[BIG_BUFFER_SIZE+1];
147 	char		*s,
148 			*loc,
149 			*p,
150 			*fn;
151 
152 	if (!fs || !*fs)
153 		return empty_string;
154 	memset(buffer, 0, sizeof(buffer));
155 
156 	loc = LOCAL_COPY(f->filename);
157 	fn = strrchr(loc, '/');
158 	*fn++ = 0;
159 	if ((p = strrchr(loc, '/')))
160 		*p++ = 0;
161 	/* fn should point to the filename and p to the dir */
162 	/*
163 	 * init the dir keeper
164 	 * or cmp the old dir with the new
165 	 */
166 	if (dirbuff && (!*dirbuff || strcmp(dirbuff, p)))
167 	{
168 		strcpy(dirbuff, p);
169 		if (fp)
170 			fprintf(fp, "\nDirectory [ %s ]\n", dirbuff);
171 		else
172 			return NULL;
173 	}
174 	/* size bitrate [time] filename */
175 	s = buffer;
176 	while (*fs)
177 	{
178 		if (*fs == '%')
179 		{
180 			int prec = 0, fl = 0;
181 			fs++;
182 			if (isdigit(*fs))
183 			{
184 				prec = strtol(fs, &fs, 0);
185 				if (*fs == '.')
186 					fl = strtoul(fs+1, &fs, 0);
187 			}
188 			switch(*fs)
189 			{
190 				case '%':
191 					*s++ = *fs;
192 					break;
193 				case 'b':
194 					sprintf(s, "%*u", prec, f->bitrate);
195 					break;
196 				case 's':
197 					if (!prec) prec = 3;
198 					sprintf(s, "%*.*f%s", prec, fl, _GMKv(f->filesize), _GMKs(f->filesize));
199 					break;
200 				case 't':
201 					strcpy(s, print_time(f->time));
202 					break;
203 				case 'T':
204 					strcpy(s, ltoa(f->time));
205 					break;
206 				case 'f':
207 					strcpy(s, fn);
208 					break;
209 				case 'F':
210 					strcpy(s, f->filename);
211 					break;
212 				case 'S':
213 					strcpy(s, mode_str(f->stereo));
214 					break;
215 				case 'H':
216 					sprintf(s, "%*.*f", prec, fl, ((double)f->freq) / ((double)1000.0));
217 					break;
218 				case 'h':
219 					sprintf(s, "%*u", prec, f->freq);
220 					break;
221 				default:
222 					*s++ = *fs;
223 					break;
224 			}
225 		}
226 		else if (*fs == '\\')
227 		{
228 			fs++;
229 			switch(*fs)
230 			{
231 				case 'n':
232 					strcpy(s, "\n");
233 					break;
234 				case 't':
235 					strcpy(s, "\t");
236 					break;
237 				default:
238 					*s++ = *fs++;
239 			}
240 		}
241 		else
242 			*s++ = *fs;
243 		while (*s) s++;
244 		fs++;
245 	}
246 	if (fp && *buffer)
247 		fputs(buffer, fp);
248 	return buffer;
249 }
250 
251 
read_glob_dir(char * path,int globflags,glob_t * globpat,int recurse)252 int read_glob_dir(char *path, int globflags, glob_t *globpat, int recurse)
253 {
254 	char	buffer[BIG_BUFFER_SIZE+1];
255 
256 	sprintf(buffer, "%s/*", path);
257 	bsd_glob(buffer, globflags, NULL, globpat);
258 	if (recurse)
259 	{
260 		int i = 0;
261 		int old_glpathc = globpat->gl_pathc;
262 		for (i = 0; i < old_glpathc; i++)
263 		{
264 			char *fn;
265 			fn = globpat->gl_pathv[i];
266 			if (fn[strlen(fn)-1] != '/')
267 				continue;
268 			sprintf(buffer, "%s*", fn);
269 			bsd_glob(buffer, globflags|GLOB_APPEND, NULL, globpat);
270 		}
271 		while (i < globpat->gl_pathc)
272 		{
273 			for (i = old_glpathc, old_glpathc = globpat->gl_pathc; i < old_glpathc; i++)
274 			{
275 				char *fn;
276 				fn = globpat->gl_pathv[i];
277 				if (fn[strlen(fn)-1] != '/')
278 					continue;
279 				sprintf(buffer, "%s*", fn);
280 				bsd_glob(buffer, globflags|GLOB_APPEND, NULL, globpat);
281 			}
282 		}
283 	}
284 	return 0;
285 }
286 
print_mp3(char * pattern,char * format,int freq,int number,int bitrate)287 unsigned int print_mp3(char *pattern, char *format, int freq, int number, int bitrate)
288 {
289 unsigned int count = 0;
290 Files *new;
291 char dir[BIG_BUFFER_SIZE];
292 char *fs = NULL;
293 	*dir = 0;
294 	for (new = fserv_files; new; new = new->next)
295 	{
296 		if (!pattern || (pattern && wild_match(pattern, new->filename)))
297 		{
298 			char *p;
299 			p = strrchr(new->filename, '/');
300 			p++;
301 			if (do_hook(MODULE_LIST, "FS: File \"%s\" %s %u %lu %lu %u", p, mode_str(new->stereo), new->bitrate, new->time, new->filesize, new->freq))
302 			{
303 				if ((bitrate != -1) && (new->bitrate != bitrate))
304 					continue;
305 				if ((freq != -1) && (new->freq != freq))
306 					continue;
307 				if (!format || !*format)
308 					put_it("%s \"%s\" %s %dk [%s]", FSstr, p, mode_str(new->stereo), new->bitrate, print_time(new->time));
309 				else
310 				{
311 					if ((fs = make_mp3_string(NULL, new, format, dir)))
312 						put_it("%s %s", FSstr, fs);
313 					else
314 						put_it("%s %s", FSstr, make_mp3_string(NULL, new, format, dir));
315 				}
316 			}
317 			if ((number > 0) && (count == number))
318 				break;
319 			count++;
320 		}
321 	}
322 	return count;
323 }
324 
BUILT_IN_DLL(print_fserv)325 BUILT_IN_DLL(print_fserv)
326 {
327 	int	count = 0;
328 	int	bitrate = -1;
329 	int	number = -1;
330 	int	freq = -1;
331 	char 	*fs_output = NULL;
332 	char	*tmp_pat = NULL;
333 
334 	if ((get_dllstring_var("fserv_format")))
335 		fs_output = m_strdup(get_dllstring_var("fserv_format"));
336 	if (args && *args)
337 	{
338 		char *tmp;
339 		while ((tmp = next_arg(args, &args)) && *tmp)
340 		{
341 			int len;
342 			len = strlen(tmp);
343 			if (!my_strnicmp(tmp, "-BITRATE", len))
344 			{
345 				if ((tmp = next_arg(args, &args)))
346 					bitrate = (unsigned int) my_atol(tmp);
347 			}
348 			else if (!my_strnicmp(tmp, "-COUNT", len))
349 			{
350 				if ((tmp = next_arg(args, &args)))
351 					number = (unsigned int) my_atol(tmp);
352 			}
353 			else if (!my_strnicmp(tmp, "-FREQ", 3))
354 			{
355 				if ((tmp = next_arg(args, &args)))
356 					freq = (unsigned int)my_atol(tmp);
357 			}
358 			else if (!my_strnicmp(tmp, "-FORMAT", 3))
359 			{
360 				if ((tmp = new_next_arg(args, &args)))
361 					malloc_strcpy(&fs_output, tmp);
362 			}
363 			else
364 			{
365 				count += print_mp3(tmp, fs_output, freq, number, bitrate);
366 				m_s3cat(&tmp_pat, " ", tmp);
367 			}
368 		}
369 	}
370 	else
371 		count += print_mp3(NULL, fs_output, freq, number, bitrate);
372 
373 	if (do_hook(MODULE_LIST, "FS: Found %d %s", count, tmp_pat ? tmp_pat : "*"))
374 		put_it("%s found %d files matching \"%s\"", FSstr, count, tmp_pat ? tmp_pat : "*");
375 	new_free(&tmp_pat);
376 	new_free(&fs_output);
377 }
378 
_get_input(int file,unsigned char * bp,int size)379 int _get_input(int file, unsigned char *bp, int size)
380 {
381 	if (read(file,  bp, size) != size)
382 		return -1;
383 	return 0;
384 }
385 
readsync(int file)386 static inline int readsync(int file)
387 {
388 	_bptr=0;
389 	_buffer[0]=_buffer[1];
390 	_buffer[1]=_buffer[2];
391 	_buffer[2]=_buffer[3];
392 	return _get_input(file, &_buffer[3], 1);
393 }
394 
395 
_fillbfr(int file,unsigned int size)396 static inline int _fillbfr(int file, unsigned int size)
397 {
398 	_bptr=0;
399         return _get_input(file, _buffer, size);
400 }
401 
402 
_getbits(int n)403 static inline unsigned int _getbits(int n)
404 {
405 	unsigned int	pos,
406 			ret_value;
407 
408         pos = _bptr >> 3;
409 	ret_value = _buffer[pos] << 24 |
410 		    _buffer[pos+1] << 16 |
411 		    _buffer[pos+2] << 8 |
412 		    _buffer[pos+3];
413         ret_value <<= _bptr & 7;
414         ret_value >>= 32 - n;
415         _bptr += n;
416         return ret_value;
417 }
418 
419 
420 /*
421  * header and side info parsing stuff ******************************************
422  */
parse_header(AUDIO_HEADER * header)423 static inline void parse_header(AUDIO_HEADER *header)
424 {
425         header->IDex=_getbits(1);
426         header->ID=_getbits(1);
427         header->layer=_getbits(2);
428         header->protection_bit=_getbits(1);
429         header->bitrate_index=_getbits(4);
430         header->sampling_frequency=_getbits(2);
431         header->padding_bit=_getbits(1);
432         header->private_bit=_getbits(1);
433         header->mode=_getbits(2);
434         header->mode_extension=_getbits(2);
435         if (!header->mode)
436         	header->mode_extension=0;
437         header->copyright=_getbits(1);
438         header->original=_getbits(1);
439         header->emphasis=_getbits(2);
440 
441 	header->stereo = (header->mode == 3) ? 1 : 2;
442 	header->true_layer = 4 - header->layer;
443 }
444 
gethdr(int file,AUDIO_HEADER * header)445 int gethdr(int file, AUDIO_HEADER *header)
446 {
447 	int	retval;
448 
449 	if ((retval=_fillbfr(file, 4)))
450 		return retval;
451 
452 	while (_getbits(11) != 0x7ff)
453 	{
454 		if ((retval=readsync(file))!=0)
455 			return retval;
456 	}
457 	parse_header(header);
458 	return 0;
459 }
460 
get_bitrate(char * filename,time_t * mp3_time,unsigned int * freq_rate,int * id3,unsigned long * filesize,int * stereo)461 long get_bitrate(char *filename, time_t *mp3_time, unsigned int *freq_rate, int *id3, unsigned long *filesize, int *stereo)
462 {
463 	short t_bitrate[2][3][15] = {{
464 	{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256},
465 	{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160},
466 	{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160}
467 	},{
468 	{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448},
469 	{0,32,48,56,64,80,96,112,128,160,192,224,256,320,384},
470 	{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320}
471 	}};
472 
473 	int t_sampling_frequency[2][2][3] = {
474 		{ /* MPEG 2.5 samplerates */
475   			{ 11025, 12000, 8000},
476 			{ 0,0,0 }
477 		},{ /* MPEG 2.0/1.0 samplerates */
478 			{ 22050 , 24000 , 16000},
479 			{ 44100 , 48000 , 32000}
480 		}
481 	};
482 
483 	AUDIO_HEADER header;
484 	unsigned long btr = 0;
485 	int l = -1;
486 	struct stat	st;
487 	unsigned long	framesize = 0,
488 			totalframes = 0;
489 
490 	if (freq_rate)
491 		*freq_rate =0;
492 	if (id3)
493 		*id3 = 0;
494 	if ((l = open(filename, O_RDONLY)) == -1)
495 		return 0;
496 	gethdr(l, &header);
497 	if (header.ID > 1 || header.layer > 2 || header.bitrate_index > 14)
498 	{
499 		close(l);
500 		return 0;
501 	}
502 	btr = t_bitrate[header.ID][3-header.layer][header.bitrate_index];
503 
504 	fstat(l, &st);
505 	if (t_sampling_frequency[header.IDex][header.ID][header.sampling_frequency] > 0)
506 		framesize = (header.ID ? 144000 : 72000) * btr / t_sampling_frequency[header.IDex][header.ID][header.sampling_frequency];
507 	totalframes = (st.st_size / (framesize + 1)) - 1;
508 	if (t_sampling_frequency[header.IDex][header.ID][header.sampling_frequency] > 0)
509 		*mp3_time = (time_t) (totalframes * (header.ID==0?576:1152)/t_sampling_frequency[header.IDex][header.ID][header.sampling_frequency]);
510 	*filesize = st.st_size;
511 
512 	if (freq_rate)
513 		*freq_rate = t_sampling_frequency[header.IDex][header.ID][header.sampling_frequency];
514 	if (id3)
515 	{
516 		char	buffer[200];
517 		lseek(l, SEEK_END, -128);
518 		if (read(l, buffer, 128) > 0)
519 			if (!strncmp(buffer, "TAG", 3))
520 				*id3 = 1;
521 	}
522 	*stereo = header.mode;
523 	close(l);
524 	return btr;
525 }
526 
527 
528 
BUILT_IN_DLL(unload_fserv)529 BUILT_IN_DLL(unload_fserv)
530 {
531 	Files	*new, *tmp;
532 	int	count = 0;
533 	if (!args || !*args)
534 	{
535 		while ((new = fserv_files))
536 		{
537 			tmp = fserv_files->next;
538 			new_free(&new->filename);
539 			statistics.total_filesize -= new->filesize;
540 			new_free(&new);
541 			fserv_files = tmp;
542 			count++;
543 		}
544 	}
545 	else
546 	{
547 		char	*pat;
548 
549 		while ((pat = new_next_arg(args, &args)))
550 		{
551 			if (!pat || !*pat)
552 				break;
553 			if ((new = (Files *)remove_from_list((List **)&fserv_files, pat)))
554 			{
555 				new_free(&new->filename);
556 				statistics.total_filesize -= new->filesize;
557 				new_free(&new);
558 				count++;
559 			}
560 		}
561 	}
562 	if (do_hook(MODULE_LIST, "FS: Clear %d", count))
563 		put_it("%s cleared %d entries", FSstr, count);
564 	statistics.total_files -= count;
565 }
566 
file_size(char * filename)567 off_t file_size (char *filename)
568 {
569 	struct stat statbuf;
570 
571 	if (!stat(filename, &statbuf))
572 		return (off_t)(statbuf.st_size);
573 	else
574 		return -1;
575 }
576 
scan_mp3_dir(char * path,int recurse,int reload)577 unsigned int scan_mp3_dir(char *path, int recurse, int reload)
578 {
579 	int	mt = 0;
580 	glob_t	globpat;
581 	int	i = 0;
582 	Files	*new;
583 	int	count = 0;
584 	memset(&globpat, 0, sizeof(glob_t));
585 	read_glob_dir(path, GLOB_MARK|GLOB_NOSORT, &globpat, recurse);
586 	for (i = 0; i < globpat.gl_pathc; i++)
587 	{
588 		char	*fn;
589 		fn = globpat.gl_pathv[i];
590 		if (fn[strlen(fn)-1] == '/')
591 			continue;
592 		if (!(mt = wild_match(DEFAULT_FILEMASK, fn)))
593 			continue;
594 		if (reload && find_in_list((List **)&fserv_files, globpat.gl_pathv[i], 0))
595 			continue;
596 		new = (Files *) new_malloc(sizeof(Files));
597 		new->filename = m_strdup(fn);
598 		new->bitrate = get_bitrate(fn, &new->time, &new->freq, &new->id3, &new->filesize, &new->stereo);
599 		if (new->filesize)
600 		{
601 			add_to_list((List **)&fserv_files, (List *)new);
602 			statistics.total_files++;
603 			statistics.total_filesize += new->filesize;
604 			count++;
605 		}
606 		else
607 		{
608 			new_free(&new->filename);
609 			new_free(&new);
610 		}
611 	}
612 	bsd_globfree(&globpat);
613 	return count;
614 }
615 
BUILT_IN_DLL(load_fserv)616 BUILT_IN_DLL(load_fserv)
617 {
618 	char	*path = NULL;
619 	int	recurse = DEFAULT_RECURSE;
620 	char	*pch;
621 	int	count = 0;
622 	int	reload = 0;
623 
624 	if (command && !my_stricmp(command, "FSRELOAD"))
625 		reload = 1;
626 	if (args && *args)
627 	{
628 		while ((path = next_arg(args, &args)) && *path)
629 		{
630 			int len = strlen(path);
631 			if (!my_strnicmp(path, "-recurse", len))
632 			{
633 				recurse ^= 1;
634 				continue;
635 			}
636 			count += scan_mp3_dir(path, recurse, reload);
637 		}
638 		goto fs_print_out;
639 	}
640 
641 	path = get_dllstring_var("fserv_dir");
642 
643 	if (!path || !*path)
644 	{
645 		if (do_hook(MODULE_LIST, "FS: Error no fserv_dir path"))
646 			put_it("%s No path. /set fserv_dir first.", FSstr);
647 		return;
648 	}
649 
650 	pch = LOCAL_COPY(path);
651 	while ((path = next_arg(pch, &pch)))
652 		count += scan_mp3_dir(path, recurse, reload);
653 fs_print_out:
654 	if (do_hook(MODULE_LIST, "FS: Load %d", count))
655 	{
656 		if (!fserv_files || !count)
657 			put_it("%s Could not read dir", FSstr);
658 		else
659 			put_it("%s found %d files", FSstr, count);
660 	}
661 	return;
662 }
663 
search_list(char * nick,char * pat,int wild)664 Files *search_list(char *nick, char *pat, int wild)
665 {
666 	Files	*new;
667 	int	dcc_send_num = 0;
668 	int	dcc_queue_num = 0;
669 	char	*p;
670 	char	buffer[BIG_BUFFER_SIZE+1];
671 	int	num_to_match;
672 
673 	num_to_match = get_dllint_var("fserv_max_match");
674 	if (wild)
675 	{
676 		int	count = 0;
677 
678 		sprintf(buffer, "*%s*", pat);
679 		while ((p = strchr(buffer, ' ')))
680 			*p = '*';
681 		dcc_send_num = get_active_count();
682 		dcc_queue_num = get_num_queue();
683 		for (new = fserv_files; new; new = new->next)
684 		{
685 			p = strrchr(new->filename, '/');
686 			p++;
687 			if (!wild_match(buffer, p))
688 				continue;
689 
690 			if (!count)
691 				if (do_hook(MODULE_LIST, "FS: SearchHeader %s %s %d %d %d %d", nick, buffer, dcc_send_num, get_int_var(DCC_SEND_LIMIT_VAR), dcc_queue_num, get_int_var(DCC_QUEUE_LIMIT_VAR)))
692 					queue_send_to_server(from_server, "PRIVMSG %s :Matches for %s. Copy and Paste in channel to request. (Slots:%d/%d), (Queue:%d/%d)", nick, buffer, dcc_send_num, get_int_var(DCC_SEND_LIMIT_VAR), dcc_queue_num, get_int_var(DCC_QUEUE_LIMIT_VAR));
693 			count++;
694 			if (!num_to_match || (count < num_to_match))
695 			{
696 				if (do_hook(MODULE_LIST, "FS: SearchList %s \"%s\" %u %u %lu %lu", nick, p, new->bitrate, new->freq, new->filesize, new->time))
697 					queue_send_to_server(from_server, "PRIVMSG %s :!%s %s %dk [%s]", nick, get_server_nickname(from_server), p, new->bitrate, print_time(new->time));
698 			}
699 		}
700 		if (num_to_match && (count > num_to_match))
701 		{
702 			if (do_hook(MODULE_LIST, "FS: SearchTooMany %s %d", nick, count))
703 				queue_send_to_server(from_server, "PRIVMSG %s :Too Many Matches[%d]", nick, count);
704 		}
705 		else if (count)
706 		{
707 			if (do_hook(MODULE_LIST, "FS: SearchResults %s %d", nick, count))
708 				queue_send_to_server(from_server, "PRIVMSG %s :..... Total %d files found", nick, count);
709 		}
710 		return NULL;
711 	}
712 	for (new = fserv_files; new; new = new->next)
713 	{
714 		p = strrchr(new->filename, '/');
715 		p++;
716 		if (my_stricmp(pat, p))
717 			continue;
718 		return new;
719 	}
720 	return NULL;
721 }
722 
make_temp_list(char * nick)723 char *make_temp_list(char *nick)
724 {
725 	Files *file;
726 	FILE *fp;
727 	const time_t when = now;
728 	int count;
729 	char *fmt, *name;
730 	char buf[BIG_BUFFER_SIZE + 1];
731 
732 	if (fserv_files == NULL)
733 		return NULL;
734 
735 	name = get_dllstring_var("fserv_filename");
736 	if (name != NULL && *name != '\0')
737 	{
738 		char *real_name = expand_twiddle(name);
739 
740 		if (real_name == NULL || *real_name == '\0')
741 			return NULL;
742 		fp = fopen(real_name, "w");
743 		new_free(&real_name);
744 		if (fp == NULL)
745 			return NULL;
746 	}
747 	else
748 	{
749 		int fd;
750 		static char template[sizeof("fserv_XXXXXX")];
751 
752 		name = strcpy(template, "fserv_XXXXXX");
753 		fd = mkstemp(template);
754 		if (fd == -1)
755 			return NULL;
756 		fp = fdopen(fd, "w");
757 		if (fp == NULL)
758 		{
759 			close(fd);
760 			return NULL;
761 		}
762 	}
763 
764 	for (count = 0, file = fserv_files; file != NULL; file = file->next)
765 		count++;
766 	strftime(buf, sizeof(buf), "%X %d/%m/%Y", localtime(&when));
767 	fprintf(fp, "Temporary mp3 list created for %s by %s on %s with %d mp3's\n\n",
768 		nick, get_server_nickname(from_server), buf, count);
769 	fmt = get_dllstring_var("fserv_format");
770 	if (fmt == NULL || *fmt == '\0')
771 		fmt = " %6.3s %3b [%t]\t %f\n";
772 	for (*buf = '\0', file = fserv_files; file != NULL; file = file->next)
773 		make_mp3_string(fp, file, fmt, buf);
774 
775 	fclose(fp);
776 	return name;
777 }
778 
BUILT_IN_DLL(list_fserv)779 BUILT_IN_DLL(list_fserv)
780 {
781 	char *nam;
782 	if (!get_dllstring_var("fserv_filename"))
783 	{
784 		put_it("%s /set fserv_filename first", FSstr);
785 		return;
786 	}
787 	if ((nam = make_temp_list(get_server_nickname(from_server))))
788 		malloc_strcpy(&fserv_filename, nam);
789 	return;
790 }
791 
search_proc(char * which,char * str,char ** unused)792 int search_proc(char *which, char *str, char **unused)
793 {
794 	char	*loc,
795 		*chan = NULL,
796 		*nick,
797 		*command,
798 		*chan_list;
799 	char	buffer[BIG_BUFFER_SIZE+1];
800 
801 	loc = LOCAL_COPY(str);
802 	chan_list = get_dllstring_var("fserv_chan");
803 	nick = next_arg(loc, &loc);
804 
805 	if (my_stricmp(which, "MSG"))
806 	{
807 		chan = next_arg(loc, &loc);
808 		command = next_arg(loc, &loc);
809 	}
810 	else
811 		command = next_arg(loc, &loc);
812 
813 	if (!get_dllint_var("fserv"))
814 		return 1;
815 	if (chan_list && *chan_list && chan)
816 	{
817 		char	*t,
818 			*ch;
819 		int got_it = 0;
820 		ch = LOCAL_COPY(chan_list);
821 		if (*ch == '*')
822 			got_it = 1;
823 		else
824 		{
825 			while ((t = next_in_comma_list(ch, &ch)) && *t)
826 				if (!my_stricmp(t, chan))
827 					got_it = 1;
828 		}
829 		if (!got_it)
830 			return 1;
831 	}
832 	if (command && *command == '@')
833 	{
834 		char *p;
835 		command++;
836 		if (!*command)
837 			return 1;
838 		if (loc && *loc && (!my_stricmp(command, "locate") || !my_stricmp(command, "find")))
839 		{
840 			search_list(nick, loc, 1);
841 			if (do_hook(MODULE_LIST, "FS: Search %s %s \"%s\"", nick, chan ? chan : "*", loc))
842 				put_it("%s got nick %s in %s searching for \"%s\"" , FSstr, nick, chan ? chan : "*", loc);
843 			return 1;
844 		}
845 		if ((p = strchr(command, '-')))
846 		{
847 			*p++ = 0;
848 			if (!*p || my_stricmp(command, get_server_nickname(from_server)))
849 				return 1;
850 			if (!my_stricmp("que", command))
851 			{
852 				/* check queue */
853 				return 1;
854 			}
855 			if (!my_stricmp("stats", command))
856 			{
857 				/* print stats */
858 				return 1;
859 			}
860 			if (!my_stricmp("remove", command))
861 			{
862 				/* remove from queue */
863 				return 1;
864 			}
865 		}
866 	}
867 	if (command && *command == '!')
868 	{
869 		command++;
870 		if (!*command) return 1;
871 		if (!my_stricmp(get_server_nickname(from_server), command) && loc && *loc)
872 		{
873 			Files	*fn = NULL;
874 			if ((fn = search_list(nick, loc, 0)))
875 			{
876 				int	send_num,
877 					queue_num;
878 				send_num = get_active_count();
879 				queue_num = get_num_queue();
880 				if (do_hook(MODULE_LIST, "FS: Sending %s \"%s\" $lu", nick, fn->filename, fn->filesize))
881 					put_it("%s sending %s \"%s\" %lu", FSstr, nick, fn->filename, fn->filesize);
882 				sprintf(buffer, "%s \"%s\"", nick, fn->filename);
883 				if (send_num > get_int_var(DCC_SEND_LIMIT_VAR))
884 				{
885 					pack *ptr = NULL;
886 					if (queue_num < get_int_var(DCC_QUEUE_LIMIT_VAR))
887 					{
888 						sprintf(buffer, "\"%s\"", fn->filename);
889 						ptr = (pack *)alloca(sizeof(pack));
890 						memset(ptr, 0, sizeof(pack));
891 						ptr->file = LOCAL_COPY(buffer);
892 						ptr->desc = LOCAL_COPY(buffer);
893 						ptr->numfiles = 1;
894 						ptr->size = fn->filesize;
895 						ptr->server = from_server;
896 						do_hook(MODULE_LIST, "FS: Queue Add %s %s", nick, buffer);
897 
898 						if (add_to_queue(nick, "SEND", ptr))
899 						{
900 							statistics.files_served++;
901 							statistics.filesize_served += fn->filesize;
902 						}
903 						else if (do_hook(MODULE_LIST, "FS: QueueFile %s %s", nick, buffer))
904 							queue_send_to_server(from_server, "PRIVMSG %s :Queued File %s", nick, buffer);
905 					} else if (do_hook(MODULE_LIST, "FS: Queue Full %s", nick))
906 						queue_send_to_server(from_server, "PRIVMSG %s :Queue is full, try again later.", nick);
907 				}
908 				else
909 				{
910 					dcc_filesend("SEND", buffer);
911 					statistics.files_served++;
912 					statistics.filesize_served += fn->filesize;
913 				}
914 			}
915 		}
916 		else if (!my_stricmp(get_server_nickname(from_server), command))
917 		{
918 			char	*name = NULL;
919 			if (fserv_filename || (name = make_temp_list(nick)))
920 			{
921 				sprintf(buffer, "%s %s", nick, fserv_filename ? fserv_filename : name);
922 				dcc_filesend("SEND", buffer);
923 			}
924 		}
925 	}
926 	return 1;
927 }
928 
impress_me(void * args)929 void impress_me(void *args)
930 {
931 	int		timer;
932 	char		*ch = NULL;
933 	ChannelList	*chan= NULL;
934 
935 	timer = get_dllint_var("fserv_time");
936 	if (timer < DEFAULT_IMPRESS_TIME)
937 		timer = DEFAULT_IMPRESS_TIME;
938 	if (!(ch = get_dllstring_var("fserv_chan")) || !*ch)
939 		ch = NULL;
940 	else
941 		ch = m_strdup(ch);
942 	chan = get_server_channels(from_server);
943 	if (!ch)
944 		ch = m_strdup(get_current_channel_by_refnum(0));
945 	else
946 	{
947 		char	*c,
948 			*p;
949 
950 		c = LOCAL_COPY(ch);
951 		ch = NULL;
952 		if (*c == '*')
953 		{
954 			ChannelList *chan;
955 			for (chan = get_server_channels(from_server); chan; chan=chan->next)
956 				m_s3cat(&ch, ",", chan->channel);
957 		}
958 		else
959 		{
960 			ChannelList *tmpchan;
961 			while ((p = next_in_comma_list(c, &c)) && *p)
962 			{
963 				if ((tmpchan = (ChannelList *)find_in_list((List **)&chan, p, 0)))
964 					m_s3cat(&ch, ",", p);
965 			}
966 		}
967 	}
968 	if (fserv_files && get_dllint_var("fserv_impress"))
969 	{
970 		unsigned long	l;
971 		Files		*new;
972 
973 		l = random_number(0L) % statistics.total_files;
974 		for (new = fserv_files; new && l; new = new->next, l--)
975 			;
976 		if (new && new->bitrate)
977 		{
978 			char	frq[30],
979 				size[40],
980 				*p;
981 			p = strrchr(new->filename, '/');
982 			p++;
983 			if (do_hook(MODULE_LIST, "FS: Impress %s \"%s\" %lu %u %u %s %lu",ch, p, new->filesize, new->bitrate, new->freq, mode_str(new->stereo), new->time))
984 			{
985 				sprintf(frq, "%3.1f", ((double)new->freq)/1000.0);
986 				sprintf(size, "%4.3f%s", _GMKv(new->filesize), _GMKs(new->filesize));
987 				queue_send_to_server(from_server, "PRIVMSG %s :[  !%s %s  ] [%s %uKbps %sKhz %s]-[%s]",
988 					ch, get_server_nickname(from_server), p,
989 					size, new->bitrate, frq,
990 					mode_str(new->stereo),
991 					print_time(new->time));
992 			}
993 		}
994 	}
995 	add_timer(0, empty_string, timer * 1000, 1, impress_me, NULL, NULL, -1, "fserv");
996 	new_free(&ch);
997 }
998 
BUILT_IN_FUNCTION(func_convert_mp3time)999 BUILT_IN_FUNCTION(func_convert_mp3time)
1000 {
1001 	int	hours,
1002 		minutes,
1003 		seconds;
1004 	if (!input)
1005 		return m_strdup(empty_string);
1006 	seconds = my_atol(input);
1007 	hours = seconds / ( 60 * 60 );
1008 	minutes = seconds / 60;
1009 	seconds = seconds % 60;
1010 	return m_sprintf("[%02d:%02d:%02d]", hours, minutes, seconds);
1011 }
1012 
BUILT_IN_DLL(stats_fserv)1013 BUILT_IN_DLL(stats_fserv)
1014 {
1015 	put_it("%s\t File Server Statistics From %s", FSstr, my_ctime(statistics.starttime));
1016 	put_it("%s\t Fserv is [%s] Impress is [%s] %d seconds with %d matches allowed", FSstr, on_off(get_dllint_var("fserv")), on_off(get_dllint_var("fserv_impress")), get_dllint_var("fserv_time"), get_dllint_var("fserv_max_match"));
1017 	put_it("%s\t Files available %lu for %4.3f%s",FSstr, statistics.total_files, _GMKv(statistics.total_filesize), _GMKs(statistics.total_filesize));
1018 	put_it("%s\t Files served %lu for %4.3f%s", FSstr, statistics.files_served, _GMKv(statistics.filesize_served), _GMKs(statistics.filesize_served));
1019 }
1020 
1021 
1022 
BUILT_IN_DLL(save_fserv)1023 BUILT_IN_DLL(save_fserv)
1024 {
1025 char bogus[] = "fserv";
1026 FILE *fp;
1027 char buffer[BIG_BUFFER_SIZE];
1028 char *p;
1029 char *fserv_savname = NULL;
1030 	sprintf(buffer, "%s/fserv.sav", get_string_var(CTOOLZ_DIR_VAR));
1031 	fserv_savname  = expand_twiddle(buffer);
1032 	if (!(fp = fopen(fserv_savname, "w")))
1033 	{
1034 		new_free(&fserv_savname);
1035 		return;
1036 	}
1037 	fprintf(fp, "%s %s\n", bogus, on_off(get_dllint_var("fserv")));
1038 	if ((p = get_dllstring_var("fserv_dir")))
1039 		fprintf(fp, "%s%s %s\n", bogus, "_dir", p);
1040 	if ((p = get_dllstring_var("fserv_chan")))
1041 		fprintf(fp, "%s%s %s\n", bogus, "_chan", p);
1042 	if ((p = get_dllstring_var("fserv_filename")))
1043 		fprintf(fp, "%s%s %s\n", bogus, "_filename", p);
1044 	if ((p = get_dllstring_var("fserv_format")))
1045 		fprintf(fp, "%s%s %s\n", bogus, "_format", p);
1046 	fprintf(fp, "%s%s %u\n", bogus, "_time", get_dllint_var("fserv_time"));
1047 	fprintf(fp, "%s%s %u\n", bogus, "_max_match", get_dllint_var("fserv_max_match"));
1048 	fprintf(fp, "%s%s %s\n", bogus, "_impress", on_off(get_dllint_var("fserv_impress")));
1049 	if (statistics.files_served)
1050 	{
1051 		fprintf(fp, "%s%s %lu\n", bogus, "_totalserved", statistics.files_served);
1052 		fprintf(fp, "%s%s %ld\n", bogus, "_totalstart", (long)statistics.starttime);
1053 		fprintf(fp, "%s%s %lu\n", bogus, "_totalsizeserved", statistics.filesize_served);
1054 	}
1055 	fclose(fp);
1056 	if ((do_hook(MODULE_LIST, "FS: Save")))
1057 		put_it("%s Done Saving.", FSstr);
1058 	new_free(&fserv_savname);
1059 }
1060 
fserv_read(char * filename)1061 void fserv_read(char *filename)
1062 {
1063 FILE *fp;
1064 char buff[IRCD_BUFFER_SIZE+1];
1065 char *fserv_savname = NULL;
1066 	fserv_savname  = expand_twiddle(filename);
1067 	if (!(fp = fopen(fserv_savname, "r")))
1068 	{
1069 		new_free(&fserv_savname);
1070 		return;
1071 	}
1072 	fgets(buff, IRCD_BUFFER_SIZE, fp);
1073 	while (!feof(fp))
1074 	{
1075 		char *p;
1076 		chop(buff, 1);
1077 		if ((p = strchr(buff, ' ')))
1078 		{
1079 			*p++ = 0;
1080 
1081 			if (!my_strnicmp(buff, "fserv_totalserved", 17))
1082 				statistics.files_served = strtoul(p, NULL, 0);
1083 			else if (!my_strnicmp(buff, "fserv_totalsizeserved", 17))
1084 				statistics.filesize_served = strtoul(p, NULL, 0);
1085 			else if (!my_strnicmp(buff, "fserv_totalserved", 17))
1086 				statistics.starttime = strtoul(p, NULL, 0);
1087 			else
1088 			{
1089 				if (*p > '0' && *p < '9')
1090 				{
1091 					int val;
1092 					val = my_atol(p);
1093 					set_dllint_var(buff, val);
1094 				}
1095 				else if (!my_stricmp(p, "ON"))
1096 					set_dllint_var(buff, 1);
1097 				else if (!my_stricmp(p, "OFF"))
1098 					set_dllint_var(buff, 0);
1099 				else
1100 					set_dllstring_var(buff, p);
1101 			}
1102 		}
1103 		fgets(buff, IRCD_BUFFER_SIZE, fp);
1104 	}
1105 	fclose(fp);
1106 }
1107 
BUILT_IN_DLL(help_fserv)1108 BUILT_IN_DLL(help_fserv)
1109 {
1110 	put_it("%s FServ %s by Colten Edwards aka panasync", FSstr, AUTO_VERSION);
1111 	put_it("%s [Sets]", FSstr);
1112 	put_it("%s fserv on/off  fserv functions. Default is %s", FSstr, on_off(DEFAULT_FSERV));
1113 	put_it("%s fserv_dir path [path]", FSstr);
1114 	put_it("%s fserv_chan #chan[,#chan2]", FSstr);
1115 	put_it("%s fserv_time seconds between displays of random mp3. Default is %d", FSstr, DEFAULT_IMPRESS_TIME);
1116 	put_it("%s fserv_max_match defines how many matches allowed. Default is %d", FSstr, DEFAULT_MAX_MATCH);
1117 	put_it("%s fserv_impress on/off public display of random mp3. Default is %s", FSstr, on_off(DEFAULT_IMPRESS));
1118 	put_it("%s", FSstr);
1119 	put_it("%s channel commands are @find pattern or @locate pattern", FSstr);
1120 	put_it("%s !nick filename to send a file to nick requesting", FSstr);
1121 	put_it("%s a /msg to the nick can be used instead of a public", FSstr);
1122 	put_it("%s a $mp3time() function as well as a hook are provided. /on module \"FS:*\"", FSstr);
1123 	put_it("%s    more help available with /help", FSstr);
1124 }
1125 
Fserv_Lock(IrcCommandDll ** intp,Function_ptr * global_table)1126 int Fserv_Lock(IrcCommandDll **intp, Function_ptr *global_table)
1127 {
1128 	return 1;
1129 }
1130 
Fserv_Version(IrcCommandDll ** intp)1131 char *Fserv_Version(IrcCommandDll **intp)
1132 {
1133 	return AUTO_VERSION;
1134 }
1135 
1136 
Fserv_Init(IrcCommandDll ** intp,Function_ptr * global_table)1137 int Fserv_Init(IrcCommandDll **intp, Function_ptr *global_table)
1138 {
1139 char buffer[BIG_BUFFER_SIZE+1];
1140 	initialize_module("Fserv");
1141 	add_module_proc(VAR_PROC, "Fserv", "fserv", NULL, BOOL_TYPE_VAR, DEFAULT_FSERV, NULL, NULL);
1142 	add_module_proc(VAR_PROC, "Fserv", "fserv_dir", NULL, STR_TYPE_VAR, 0, NULL, NULL);
1143 	add_module_proc(VAR_PROC, "Fserv", "fserv_chan", NULL, STR_TYPE_VAR, 0, NULL, NULL);
1144 	add_module_proc(VAR_PROC, "Fserv", "fserv_filename", NULL, STR_TYPE_VAR, 0, NULL, NULL);
1145 	add_module_proc(VAR_PROC, "Fserv", "fserv_format", NULL, STR_TYPE_VAR, 0, NULL, NULL);
1146 	add_module_proc(VAR_PROC, "Fserv", "fserv_time", NULL, INT_TYPE_VAR, DEFAULT_IMPRESS_TIME, NULL, NULL);
1147 	add_module_proc(VAR_PROC, "Fserv", "fserv_max_match", NULL, INT_TYPE_VAR, DEFAULT_MAX_MATCH, NULL, NULL);
1148 	add_module_proc(VAR_PROC, "Fserv", "fserv_impress", NULL, BOOL_TYPE_VAR, DEFAULT_IMPRESS, NULL, NULL);
1149 
1150 	sprintf(buffer, " [-recurse] [path [path]] to load all files -recurse is a \ntoggle and can appear anywhere. Default is [%s]", on_off(DEFAULT_RECURSE));
1151 	add_module_proc(COMMAND_PROC, "Fserv", "fsload", NULL, 0, 0, load_fserv, buffer);
1152 
1153 	sprintf(buffer, " [-count #] [-freq #] [-bitrate #] [pattern] to search database locally");
1154 	add_module_proc(COMMAND_PROC, "Fserv", "fsprint", NULL, 0, 0, print_fserv, buffer);
1155 
1156 	sprintf(buffer, " to remove all files or [pat [pat]] to remove specific");
1157 	add_module_proc(COMMAND_PROC, "Fserv", "fsunload", NULL, 0, 0, unload_fserv, buffer);
1158 
1159 	add_module_proc(COMMAND_PROC, "Fserv", "fshelp", NULL, 0, 0, help_fserv, " to provide help for fserv plugin");
1160 
1161 	sprintf(buffer, " [-recurse] [path [path]] to reload all files");
1162 	add_module_proc(COMMAND_PROC, "Fserv", "fsreload", NULL, 0, 0, load_fserv, buffer);
1163 
1164 	add_module_proc(COMMAND_PROC, "Fserv", "fsstats", NULL, 0, 0, stats_fserv, " provides fserv statistics");
1165 
1166 	sprintf(buffer, " Creates list of mp3");
1167 	add_module_proc(COMMAND_PROC, "Fserv", "fslist", NULL, 0, 0, list_fserv, buffer);
1168 
1169 	sprintf(buffer, " to save your stats and settings to %s/fserv.sav", get_string_var(CTOOLZ_DIR_VAR));
1170 	add_module_proc(COMMAND_PROC, "Fserv", "fssave", NULL, 0, 0, save_fserv, buffer);
1171 
1172 
1173 	add_module_proc(ALIAS_PROC, "Fserv", "mp3time", NULL, 0, 0, func_convert_mp3time, NULL);
1174         add_module_proc(HOOK_PROC, "Fserv", NULL, "*", PUBLIC_LIST, 1, NULL, search_proc);
1175         add_module_proc(HOOK_PROC, "Fserv", NULL, "*", MSG_LIST, 1, NULL, search_proc);
1176         add_module_proc(HOOK_PROC, "Fserv", NULL, "*", PUBLIC_OTHER_LIST, 1, NULL, search_proc);
1177 
1178 	add_completion_type("fsload", 3, FILE_COMPLETION);
1179 
1180 	add_timer(0, empty_string, get_dllint_var("fserv_time"), 1, impress_me, NULL, NULL, -1, "fserv");
1181 	strmcpy(FSstr, cparse(FS, NULL, NULL), sizeof(FSstr) - 1);
1182 	put_it("%s %s", FSstr, convert_output_format("$0 v$1 by panasync.", "%s %s", fserv_version, AUTO_VERSION));
1183 	sprintf(buffer, "$0+%s by panasync - $2 $3", fserv_version);
1184 	fset_string_var(FORMAT_VERSION_FSET, buffer);
1185 	statistics.starttime = time(NULL);
1186 
1187 	sprintf(buffer, "%s/fserv.sav", get_string_var(CTOOLZ_DIR_VAR));
1188 	fserv_read(buffer);
1189 
1190 	put_it("%s for help with this fserv, /fshelp", FSstr);
1191 	return 0;
1192 }
1193 
1194