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