be written, so use sizeof - 1 instead of sizeof. git-svn-id: svn://svn.code.sf.net/p/bitchx/code/trunk@303 13b04d17-f746-0410-82c6-800466cd88b0
1178 lines
30 KiB
C
1178 lines
30 KiB
C
#define AUTO_VERSION "1.00"
|
||
|
||
/*
|
||
*
|
||
* Written by Colten Edwards. (C) Nov 11/99
|
||
*
|
||
*/
|
||
|
||
#include "irc.h"
|
||
#include "struct.h"
|
||
#include "dcc.h"
|
||
#include "ircaux.h"
|
||
#include "ctcp.h"
|
||
#include "cdcc.h"
|
||
#include "input.h"
|
||
#include "status.h"
|
||
#include "lastlog.h"
|
||
#include "screen.h"
|
||
#include "vars.h"
|
||
#include "misc.h"
|
||
#include "output.h"
|
||
#include "module.h"
|
||
#include "hook.h"
|
||
#include "hash2.h"
|
||
#include "bsdglob.h"
|
||
#define INIT_MODULE
|
||
#include "modval.h"
|
||
|
||
#include <sys/time.h>
|
||
#include <sys/stat.h>
|
||
|
||
#define cparse convert_output_format
|
||
#define FS "%PFS%w:%n"
|
||
|
||
#define DEFAULT_IMPRESS_TIME 30
|
||
#define DEFAULT_FSERV 1
|
||
#define DEFAULT_IMPRESS 0
|
||
#define DEFAULT_MAX_MATCH 4
|
||
#define DEFAULT_RECURSE 1
|
||
#define DEFAULT_FILEMASK "*.mp3"
|
||
|
||
|
||
char fserv_version[] = "Fserv 1.000";
|
||
char *fserv_filename = NULL;
|
||
char FSstr[80] = "FS:";
|
||
|
||
typedef struct _Stats {
|
||
unsigned long total_files;
|
||
unsigned long total_filesize;
|
||
unsigned long files_served;
|
||
unsigned long filesize_served;
|
||
double max_speed;
|
||
time_t starttime;
|
||
} Stats;
|
||
|
||
Stats statistics = { 0, };
|
||
|
||
/*
|
||
* ideas.
|
||
* make it notice instead of msg the nick.
|
||
* make it allow /msg nick !filename
|
||
*/
|
||
|
||
#if 0
|
||
<Lena-:#mp3jukebox> <><>< For My List(1069 files: 4307MB) and DCC Status Type
|
||
@Lena- and @Lena--stats [(1/10) Slots Taken (0/10) Ques
|
||
Taken] [Open Slot Ready] [Bandwidth in Use: 3081cps]
|
||
[Highest Cps Record: 56.3kb/s by Grey13] [Total Files
|
||
Served: 6045] ><><>
|
||
<Gaff> [ !Gaff Is It Too Late Now.mp3 ] [2.6MB 128Kbps 44.1Khz Joint Stereo
|
||
(2m44s)]-SpR-@Gaff -> request my list-@Gaff-que -> check
|
||
que-@Gaff-stats -> check DCC stats-@Gaff-remove -> cancel
|
||
song request
|
||
#endif
|
||
|
||
typedef struct _AUDIO_HEADER {
|
||
int IDex;
|
||
int ID;
|
||
int layer;
|
||
int protection_bit;
|
||
int bitrate_index;
|
||
int sampling_frequency;
|
||
int padding_bit;
|
||
int private_bit;
|
||
int mode; /* 0 = STEREO 1 = Joint 2 = DUAL 3 = Mono */
|
||
int mode_extension;
|
||
int copyright;
|
||
int original;
|
||
int emphasis;
|
||
int stereo;
|
||
int jsbound;
|
||
int sblimit;
|
||
int true_layer;
|
||
int framesize;
|
||
} AUDIO_HEADER;
|
||
|
||
|
||
static unsigned char _buffer[32];
|
||
static int _bptr = 0;
|
||
|
||
|
||
typedef struct _files {
|
||
struct _files *next;
|
||
char *filename;
|
||
unsigned long filesize;
|
||
time_t time;
|
||
int bitrate;
|
||
int freq;
|
||
int stereo;
|
||
int id3;
|
||
} Files;
|
||
|
||
Files *fserv_files = NULL;
|
||
|
||
|
||
char *mode_str(int mode)
|
||
{
|
||
switch(mode)
|
||
{
|
||
case 0:
|
||
return "Stereo";
|
||
case 1:
|
||
return "Joint-Stereo";
|
||
case 2:
|
||
return "Dual-Channel";
|
||
case 3:
|
||
return "Mono";
|
||
}
|
||
return empty_string;
|
||
}
|
||
|
||
char *print_time(time_t input)
|
||
{
|
||
static char buff[40];
|
||
time_t seconds,
|
||
minutes;
|
||
seconds = input;
|
||
minutes = seconds / 60;
|
||
seconds = seconds % 60;
|
||
sprintf(buff, "%02u:%02u", (unsigned int)minutes, (unsigned int)seconds);
|
||
return buff;
|
||
}
|
||
|
||
char *make_mp3_string(FILE *fp, Files *f, char *fs, char *dirbuff)
|
||
{
|
||
static char buffer[BIG_BUFFER_SIZE+1];
|
||
char *s,
|
||
*loc,
|
||
*p,
|
||
*fn;
|
||
|
||
if (!fs || !*fs)
|
||
return empty_string;
|
||
memset(buffer, 0, sizeof(buffer));
|
||
|
||
loc = LOCAL_COPY(f->filename);
|
||
fn = strrchr(loc, '/');
|
||
*fn++ = 0;
|
||
if ((p = strrchr(loc, '/')))
|
||
*p++ = 0;
|
||
/* fn should point to the filename and p to the dir */
|
||
/*
|
||
* init the dir keeper
|
||
* or cmp the old dir with the new
|
||
*/
|
||
if (dirbuff && (!*dirbuff || strcmp(dirbuff, p)))
|
||
{
|
||
strcpy(dirbuff, p);
|
||
if (fp)
|
||
fprintf(fp, "\nDirectory [ %s ]\n", dirbuff);
|
||
else
|
||
return NULL;
|
||
}
|
||
/* size bitrate [time] filename */
|
||
s = buffer;
|
||
while (*fs)
|
||
{
|
||
if (*fs == '%')
|
||
{
|
||
int prec = 0, fl = 0;
|
||
fs++;
|
||
if (isdigit(*fs))
|
||
{
|
||
prec = strtol(fs, &fs, 0);
|
||
if (*fs == '.')
|
||
fl = strtoul(fs+1, &fs, 0);
|
||
}
|
||
switch(*fs)
|
||
{
|
||
case '%':
|
||
*s++ = *fs;
|
||
break;
|
||
case 'b':
|
||
sprintf(s, "%*u", prec, f->bitrate);
|
||
break;
|
||
case 's':
|
||
if (!prec) prec = 3;
|
||
sprintf(s, "%*.*f%s", prec, fl, _GMKv(f->filesize), _GMKs(f->filesize));
|
||
break;
|
||
case 't':
|
||
strcpy(s, print_time(f->time));
|
||
break;
|
||
case 'T':
|
||
strcpy(s, ltoa(f->time));
|
||
break;
|
||
case 'f':
|
||
strcpy(s, fn);
|
||
break;
|
||
case 'F':
|
||
strcpy(s, f->filename);
|
||
break;
|
||
case 'S':
|
||
strcpy(s, mode_str(f->stereo));
|
||
break;
|
||
case 'H':
|
||
sprintf(s, "%*.*f", prec, fl, ((double)f->freq) / ((double)1000.0));
|
||
break;
|
||
case 'h':
|
||
sprintf(s, "%*u", prec, f->freq);
|
||
break;
|
||
default:
|
||
*s++ = *fs;
|
||
break;
|
||
}
|
||
}
|
||
else if (*fs == '\\')
|
||
{
|
||
fs++;
|
||
switch(*fs)
|
||
{
|
||
case 'n':
|
||
strcpy(s, "\n");
|
||
break;
|
||
case 't':
|
||
strcpy(s, "\t");
|
||
break;
|
||
default:
|
||
*s++ = *fs++;
|
||
}
|
||
}
|
||
else
|
||
*s++ = *fs;
|
||
while (*s) s++;
|
||
fs++;
|
||
}
|
||
if (fp && *buffer)
|
||
fputs(buffer, fp);
|
||
return buffer;
|
||
}
|
||
|
||
|
||
int read_glob_dir(char *path, int globflags, glob_t *globpat, int recurse)
|
||
{
|
||
char buffer[BIG_BUFFER_SIZE+1];
|
||
|
||
sprintf(buffer, "%s/*", path);
|
||
bsd_glob(buffer, globflags, NULL, globpat);
|
||
if (recurse)
|
||
{
|
||
int i = 0;
|
||
int old_glpathc = globpat->gl_pathc;
|
||
for (i = 0; i < old_glpathc; i++)
|
||
{
|
||
char *fn;
|
||
fn = globpat->gl_pathv[i];
|
||
if (fn[strlen(fn)-1] != '/')
|
||
continue;
|
||
sprintf(buffer, "%s*", fn);
|
||
bsd_glob(buffer, globflags|GLOB_APPEND, NULL, globpat);
|
||
}
|
||
while (i < globpat->gl_pathc)
|
||
{
|
||
for (i = old_glpathc, old_glpathc = globpat->gl_pathc; i < old_glpathc; i++)
|
||
{
|
||
char *fn;
|
||
fn = globpat->gl_pathv[i];
|
||
if (fn[strlen(fn)-1] != '/')
|
||
continue;
|
||
sprintf(buffer, "%s*", fn);
|
||
bsd_glob(buffer, globflags|GLOB_APPEND, NULL, globpat);
|
||
}
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
unsigned int print_mp3(char *pattern, char *format, int freq, int number, int bitrate)
|
||
{
|
||
unsigned int count = 0;
|
||
Files *new;
|
||
char dir[BIG_BUFFER_SIZE];
|
||
char *fs = NULL;
|
||
*dir = 0;
|
||
for (new = fserv_files; new; new = new->next)
|
||
{
|
||
if (!pattern || (pattern && wild_match(pattern, new->filename)))
|
||
{
|
||
char *p;
|
||
p = strrchr(new->filename, '/');
|
||
p++;
|
||
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))
|
||
{
|
||
if ((bitrate != -1) && (new->bitrate != bitrate))
|
||
continue;
|
||
if ((freq != -1) && (new->freq != freq))
|
||
continue;
|
||
if (!format || !*format)
|
||
put_it("%s \"%s\" %s %dk [%s]", FSstr, p, mode_str(new->stereo), new->bitrate, print_time(new->time));
|
||
else
|
||
{
|
||
if ((fs = make_mp3_string(NULL, new, format, dir)))
|
||
put_it("%s %s", FSstr, fs);
|
||
else
|
||
put_it("%s %s", FSstr, make_mp3_string(NULL, new, format, dir));
|
||
}
|
||
}
|
||
if ((number > 0) && (count == number))
|
||
break;
|
||
count++;
|
||
}
|
||
}
|
||
return count;
|
||
}
|
||
|
||
BUILT_IN_DLL(print_fserv)
|
||
{
|
||
int count = 0;
|
||
int bitrate = -1;
|
||
int number = -1;
|
||
int freq = -1;
|
||
char *fs_output = NULL;
|
||
char *tmp_pat = NULL;
|
||
|
||
if ((get_dllstring_var("fserv_format")))
|
||
fs_output = m_strdup(get_dllstring_var("fserv_format"));
|
||
if (args && *args)
|
||
{
|
||
char *tmp;
|
||
while ((tmp = next_arg(args, &args)) && *tmp)
|
||
{
|
||
int len;
|
||
len = strlen(tmp);
|
||
if (!my_strnicmp(tmp, "-BITRATE", len))
|
||
{
|
||
if ((tmp = next_arg(args, &args)))
|
||
bitrate = (unsigned int) my_atol(tmp);
|
||
}
|
||
else if (!my_strnicmp(tmp, "-COUNT", len))
|
||
{
|
||
if ((tmp = next_arg(args, &args)))
|
||
number = (unsigned int) my_atol(tmp);
|
||
}
|
||
else if (!my_strnicmp(tmp, "-FREQ", 3))
|
||
{
|
||
if ((tmp = next_arg(args, &args)))
|
||
freq = (unsigned int)my_atol(tmp);
|
||
}
|
||
else if (!my_strnicmp(tmp, "-FORMAT", 3))
|
||
{
|
||
if ((tmp = new_next_arg(args, &args)))
|
||
malloc_strcpy(&fs_output, tmp);
|
||
}
|
||
else
|
||
{
|
||
count += print_mp3(tmp, fs_output, freq, number, bitrate);
|
||
m_s3cat(&tmp_pat, " ", tmp);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
count += print_mp3(NULL, fs_output, freq, number, bitrate);
|
||
|
||
if (do_hook(MODULE_LIST, "FS: Found %d %s", count, tmp_pat ? tmp_pat : "*"))
|
||
put_it("%s found %d files matching \"%s\"", FSstr, count, tmp_pat ? tmp_pat : "*");
|
||
new_free(&tmp_pat);
|
||
new_free(&fs_output);
|
||
}
|
||
|
||
int _get_input(int file, unsigned char *bp, int size)
|
||
{
|
||
if (read(file, bp, size) != size)
|
||
return -1;
|
||
return 0;
|
||
}
|
||
|
||
static inline int readsync(int file)
|
||
{
|
||
_bptr=0;
|
||
_buffer[0]=_buffer[1];
|
||
_buffer[1]=_buffer[2];
|
||
_buffer[2]=_buffer[3];
|
||
return _get_input(file, &_buffer[3], 1);
|
||
}
|
||
|
||
|
||
static inline int _fillbfr(int file, unsigned int size)
|
||
{
|
||
_bptr=0;
|
||
return _get_input(file, _buffer, size);
|
||
}
|
||
|
||
|
||
static inline unsigned int _getbits(int n)
|
||
{
|
||
unsigned int pos,
|
||
ret_value;
|
||
|
||
pos = _bptr >> 3;
|
||
ret_value = _buffer[pos] << 24 |
|
||
_buffer[pos+1] << 16 |
|
||
_buffer[pos+2] << 8 |
|
||
_buffer[pos+3];
|
||
ret_value <<= _bptr & 7;
|
||
ret_value >>= 32 - n;
|
||
_bptr += n;
|
||
return ret_value;
|
||
}
|
||
|
||
|
||
/*
|
||
* header and side info parsing stuff ******************************************
|
||
*/
|
||
static inline void parse_header(AUDIO_HEADER *header)
|
||
{
|
||
header->IDex=_getbits(1);
|
||
header->ID=_getbits(1);
|
||
header->layer=_getbits(2);
|
||
header->protection_bit=_getbits(1);
|
||
header->bitrate_index=_getbits(4);
|
||
header->sampling_frequency=_getbits(2);
|
||
header->padding_bit=_getbits(1);
|
||
header->private_bit=_getbits(1);
|
||
header->mode=_getbits(2);
|
||
header->mode_extension=_getbits(2);
|
||
if (!header->mode)
|
||
header->mode_extension=0;
|
||
header->copyright=_getbits(1);
|
||
header->original=_getbits(1);
|
||
header->emphasis=_getbits(2);
|
||
|
||
header->stereo = (header->mode == 3) ? 1 : 2;
|
||
header->true_layer = 4 - header->layer;
|
||
}
|
||
|
||
int gethdr(int file, AUDIO_HEADER *header)
|
||
{
|
||
int retval;
|
||
|
||
if ((retval=_fillbfr(file, 4)))
|
||
return retval;
|
||
|
||
while (_getbits(11) != 0x7ff)
|
||
{
|
||
if ((retval=readsync(file))!=0)
|
||
return retval;
|
||
}
|
||
parse_header(header);
|
||
return 0;
|
||
}
|
||
|
||
long get_bitrate(char *filename, time_t *mp3_time, unsigned int *freq_rate, int *id3, unsigned long *filesize, int *stereo)
|
||
{
|
||
short t_bitrate[2][3][15] = {{
|
||
{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256},
|
||
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160},
|
||
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160}
|
||
},{
|
||
{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448},
|
||
{0,32,48,56,64,80,96,112,128,160,192,224,256,320,384},
|
||
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320}
|
||
}};
|
||
|
||
int t_sampling_frequency[2][2][3] = {
|
||
{ /* MPEG 2.5 samplerates */
|
||
{ 11025, 12000, 8000},
|
||
{ 0,0,0 }
|
||
},{ /* MPEG 2.0/1.0 samplerates */
|
||
{ 22050 , 24000 , 16000},
|
||
{ 44100 , 48000 , 32000}
|
||
}
|
||
};
|
||
|
||
AUDIO_HEADER header;
|
||
unsigned long btr = 0;
|
||
int l = -1;
|
||
struct stat st;
|
||
unsigned long framesize = 0,
|
||
totalframes = 0;
|
||
|
||
if (freq_rate)
|
||
*freq_rate =0;
|
||
if (id3)
|
||
*id3 = 0;
|
||
if ((l = open(filename, O_RDONLY)) == -1)
|
||
return 0;
|
||
gethdr(l, &header);
|
||
if (header.ID > 1 || header.layer > 2 || header.bitrate_index > 14)
|
||
{
|
||
close(l);
|
||
return 0;
|
||
}
|
||
btr = t_bitrate[header.ID][3-header.layer][header.bitrate_index];
|
||
|
||
fstat(l, &st);
|
||
if (t_sampling_frequency[header.IDex][header.ID][header.sampling_frequency] > 0)
|
||
framesize = (header.ID ? 144000 : 72000) * btr / t_sampling_frequency[header.IDex][header.ID][header.sampling_frequency];
|
||
totalframes = (st.st_size / (framesize + 1)) - 1;
|
||
if (t_sampling_frequency[header.IDex][header.ID][header.sampling_frequency] > 0)
|
||
*mp3_time = (time_t) (totalframes * (header.ID==0?576:1152)/t_sampling_frequency[header.IDex][header.ID][header.sampling_frequency]);
|
||
*filesize = st.st_size;
|
||
|
||
if (freq_rate)
|
||
*freq_rate = t_sampling_frequency[header.IDex][header.ID][header.sampling_frequency];
|
||
if (id3)
|
||
{
|
||
char buffer[200];
|
||
lseek(l, SEEK_END, -128);
|
||
if (read(l, buffer, 128) > 0)
|
||
if (!strncmp(buffer, "TAG", 3))
|
||
*id3 = 1;
|
||
}
|
||
*stereo = header.mode;
|
||
close(l);
|
||
return btr;
|
||
}
|
||
|
||
|
||
|
||
BUILT_IN_DLL(unload_fserv)
|
||
{
|
||
Files *new, *tmp;
|
||
int count = 0;
|
||
if (!args || !*args)
|
||
{
|
||
while ((new = fserv_files))
|
||
{
|
||
tmp = fserv_files->next;
|
||
new_free(&new->filename);
|
||
statistics.total_filesize -= new->filesize;
|
||
new_free(&new);
|
||
fserv_files = tmp;
|
||
count++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
char *pat;
|
||
|
||
while ((pat = new_next_arg(args, &args)))
|
||
{
|
||
if (!pat || !*pat)
|
||
break;
|
||
if ((new = (Files *)remove_from_list((List **)&fserv_files, pat)))
|
||
{
|
||
new_free(&new->filename);
|
||
statistics.total_filesize -= new->filesize;
|
||
new_free(&new);
|
||
count++;
|
||
}
|
||
}
|
||
}
|
||
if (do_hook(MODULE_LIST, "FS: Clear %d", count))
|
||
put_it("%s cleared %d entries", FSstr, count);
|
||
statistics.total_files -= count;
|
||
}
|
||
|
||
off_t file_size (char *filename)
|
||
{
|
||
struct stat statbuf;
|
||
|
||
if (!stat(filename, &statbuf))
|
||
return (off_t)(statbuf.st_size);
|
||
else
|
||
return -1;
|
||
}
|
||
|
||
unsigned int scan_mp3_dir(char *path, int recurse, int reload)
|
||
{
|
||
int mt = 0;
|
||
glob_t globpat;
|
||
int i = 0;
|
||
Files *new;
|
||
int count = 0;
|
||
memset(&globpat, 0, sizeof(glob_t));
|
||
read_glob_dir(path, GLOB_MARK|GLOB_NOSORT, &globpat, recurse);
|
||
for (i = 0; i < globpat.gl_pathc; i++)
|
||
{
|
||
char *fn;
|
||
fn = globpat.gl_pathv[i];
|
||
if (fn[strlen(fn)-1] == '/')
|
||
continue;
|
||
if (!(mt = wild_match(DEFAULT_FILEMASK, fn)))
|
||
continue;
|
||
if (reload && find_in_list((List **)&fserv_files, globpat.gl_pathv[i], 0))
|
||
continue;
|
||
new = (Files *) new_malloc(sizeof(Files));
|
||
new->filename = m_strdup(fn);
|
||
new->bitrate = get_bitrate(fn, &new->time, &new->freq, &new->id3, &new->filesize, &new->stereo);
|
||
if (new->filesize)
|
||
{
|
||
add_to_list((List **)&fserv_files, (List *)new);
|
||
statistics.total_files++;
|
||
statistics.total_filesize += new->filesize;
|
||
count++;
|
||
}
|
||
else
|
||
{
|
||
new_free(&new->filename);
|
||
new_free(&new);
|
||
}
|
||
}
|
||
bsd_globfree(&globpat);
|
||
return count;
|
||
}
|
||
|
||
BUILT_IN_DLL(load_fserv)
|
||
{
|
||
char *path = NULL;
|
||
int recurse = DEFAULT_RECURSE;
|
||
char *pch;
|
||
int count = 0;
|
||
int reload = 0;
|
||
|
||
if (command && !my_stricmp(command, "FSRELOAD"))
|
||
reload = 1;
|
||
if (args && *args)
|
||
{
|
||
while ((path = next_arg(args, &args)) && *path)
|
||
{
|
||
int len = strlen(path);
|
||
if (!my_strnicmp(path, "-recurse", len))
|
||
{
|
||
recurse ^= 1;
|
||
continue;
|
||
}
|
||
count += scan_mp3_dir(path, recurse, reload);
|
||
}
|
||
goto fs_print_out;
|
||
}
|
||
|
||
path = get_dllstring_var("fserv_dir");
|
||
|
||
if (!path || !*path)
|
||
{
|
||
if (do_hook(MODULE_LIST, "FS: Error no fserv_dir path"))
|
||
put_it("%s No path. /set fserv_dir first.", FSstr);
|
||
return;
|
||
}
|
||
|
||
pch = LOCAL_COPY(path);
|
||
while ((path = next_arg(pch, &pch)))
|
||
count += scan_mp3_dir(path, recurse, reload);
|
||
fs_print_out:
|
||
if (do_hook(MODULE_LIST, "FS: Load %d", count))
|
||
{
|
||
if (!fserv_files || !count)
|
||
put_it("%s Could not read dir", FSstr);
|
||
else
|
||
put_it("%s found %d files", FSstr, count);
|
||
}
|
||
return;
|
||
}
|
||
|
||
Files *search_list(char *nick, char *pat, int wild)
|
||
{
|
||
Files *new;
|
||
int dcc_send_num = 0;
|
||
int dcc_queue_num = 0;
|
||
char *p;
|
||
char buffer[BIG_BUFFER_SIZE+1];
|
||
int num_to_match;
|
||
|
||
num_to_match = get_dllint_var("fserv_max_match");
|
||
if (wild)
|
||
{
|
||
int count = 0;
|
||
|
||
sprintf(buffer, "*%s*", pat);
|
||
while ((p = strchr(buffer, ' ')))
|
||
*p = '*';
|
||
dcc_send_num = get_active_count();
|
||
dcc_queue_num = get_num_queue();
|
||
for (new = fserv_files; new; new = new->next)
|
||
{
|
||
p = strrchr(new->filename, '/');
|
||
p++;
|
||
if (!wild_match(buffer, p))
|
||
continue;
|
||
|
||
if (!count)
|
||
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)))
|
||
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));
|
||
count++;
|
||
if (!num_to_match || (count < num_to_match))
|
||
{
|
||
if (do_hook(MODULE_LIST, "FS: SearchList %s \"%s\" %u %u %lu %lu", nick, p, new->bitrate, new->freq, new->filesize, new->time))
|
||
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));
|
||
}
|
||
}
|
||
if (num_to_match && (count > num_to_match))
|
||
{
|
||
if (do_hook(MODULE_LIST, "FS: SearchTooMany %s %d", nick, count))
|
||
queue_send_to_server(from_server, "PRIVMSG %s :Too Many Matches[%d]", nick, count);
|
||
}
|
||
else if (count)
|
||
{
|
||
if (do_hook(MODULE_LIST, "FS: SearchResults %s %d", nick, count))
|
||
queue_send_to_server(from_server, "PRIVMSG %s :..... Total %d files found", nick, count);
|
||
}
|
||
return NULL;
|
||
}
|
||
for (new = fserv_files; new; new = new->next)
|
||
{
|
||
p = strrchr(new->filename, '/');
|
||
p++;
|
||
if (my_stricmp(pat, p))
|
||
continue;
|
||
return new;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
|
||
char *make_temp_list(char *nick)
|
||
{
|
||
char *nam;
|
||
char *real_nam;
|
||
FILE *fp;
|
||
|
||
if (!(nam = get_dllstring_var("fserv_filename")) || !*nam)
|
||
nam = tmpnam(NULL);
|
||
real_nam = expand_twiddle(nam);
|
||
if (!fserv_files || !real_nam || !*real_nam)
|
||
{
|
||
new_free(&real_nam);
|
||
return NULL;
|
||
}
|
||
if ((fp = fopen(real_nam, "w")))
|
||
{
|
||
char buffer2[BIG_BUFFER_SIZE+1];
|
||
char *fs;
|
||
int count = 0;
|
||
|
||
time_t t = now;
|
||
Files *new;
|
||
strftime(buffer2, 200, "%X %d/%m/%Y", localtime(&t));
|
||
for (new = fserv_files; new; new = new->next)
|
||
count++;
|
||
fprintf(fp, "Temporary mp3 list created for %s by %s on %s with %d mp3's\n\n", nick, get_server_nickname(from_server), buffer2, count);
|
||
*buffer2 = 0;
|
||
if (!(fs = get_dllstring_var("fserv_format")) || !*fs)
|
||
fs = " %6.3s %3b [%t]\t %f\n";
|
||
for (new = fserv_files; new; new = new->next)
|
||
make_mp3_string(fp, new, fs, buffer2);
|
||
fclose(fp);
|
||
new_free(&real_nam);
|
||
return nam;
|
||
}
|
||
new_free(&real_nam);
|
||
return NULL;
|
||
}
|
||
|
||
BUILT_IN_DLL(list_fserv)
|
||
{
|
||
char *nam;
|
||
if (!get_dllstring_var("fserv_filename"))
|
||
{
|
||
put_it("%s /set fserv_filename first", FSstr);
|
||
return;
|
||
}
|
||
if ((nam = make_temp_list(get_server_nickname(from_server))))
|
||
malloc_strcpy(&fserv_filename, nam);
|
||
return;
|
||
}
|
||
|
||
int search_proc(char *which, char *str, char **unused)
|
||
{
|
||
char *loc,
|
||
*chan = NULL,
|
||
*nick,
|
||
*command,
|
||
*chan_list;
|
||
char buffer[BIG_BUFFER_SIZE+1];
|
||
|
||
loc = LOCAL_COPY(str);
|
||
chan_list = get_dllstring_var("fserv_chan");
|
||
nick = next_arg(loc, &loc);
|
||
|
||
if (my_stricmp(which, "MSG"))
|
||
{
|
||
chan = next_arg(loc, &loc);
|
||
command = next_arg(loc, &loc);
|
||
}
|
||
else
|
||
command = next_arg(loc, &loc);
|
||
|
||
if (!get_dllint_var("fserv"))
|
||
return 1;
|
||
if (chan_list && *chan_list && chan)
|
||
{
|
||
char *t,
|
||
*ch;
|
||
int got_it = 0;
|
||
ch = LOCAL_COPY(chan_list);
|
||
if (*ch == '*')
|
||
got_it = 1;
|
||
else
|
||
{
|
||
while ((t = next_in_comma_list(ch, &ch)) && *t)
|
||
if (!my_stricmp(t, chan))
|
||
got_it = 1;
|
||
}
|
||
if (!got_it)
|
||
return 1;
|
||
}
|
||
if (command && *command == '@')
|
||
{
|
||
char *p;
|
||
command++;
|
||
if (!*command)
|
||
return 1;
|
||
if (loc && *loc && (!my_stricmp(command, "locate") || !my_stricmp(command, "find")))
|
||
{
|
||
search_list(nick, loc, 1);
|
||
if (do_hook(MODULE_LIST, "FS: Search %s %s \"%s\"", nick, chan ? chan : "*", loc))
|
||
put_it("%s got nick %s in %s searching for \"%s\"" , FSstr, nick, chan ? chan : "*", loc);
|
||
return 1;
|
||
}
|
||
if ((p = strchr(command, '-')))
|
||
{
|
||
*p++ = 0;
|
||
if (!*p || my_stricmp(command, get_server_nickname(from_server)))
|
||
return 1;
|
||
if (!my_stricmp("que", command))
|
||
{
|
||
/* check queue */
|
||
return 1;
|
||
}
|
||
if (!my_stricmp("stats", command))
|
||
{
|
||
/* print stats */
|
||
return 1;
|
||
}
|
||
if (!my_stricmp("remove", command))
|
||
{
|
||
/* remove from queue */
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
if (command && *command == '!')
|
||
{
|
||
command++;
|
||
if (!*command) return 1;
|
||
if (!my_stricmp(get_server_nickname(from_server), command) && loc && *loc)
|
||
{
|
||
Files *fn = NULL;
|
||
if ((fn = search_list(nick, loc, 0)))
|
||
{
|
||
int send_num,
|
||
queue_num;
|
||
send_num = get_active_count();
|
||
queue_num = get_num_queue();
|
||
if (do_hook(MODULE_LIST, "FS: Sending %s \"%s\" $lu", nick, fn->filename, fn->filesize))
|
||
put_it("%s sending %s \"%s\" %lu", FSstr, nick, fn->filename, fn->filesize);
|
||
sprintf(buffer, "%s \"%s\"", nick, fn->filename);
|
||
if (send_num > get_int_var(DCC_SEND_LIMIT_VAR))
|
||
{
|
||
pack *ptr = NULL;
|
||
if (queue_num < get_int_var(DCC_QUEUE_LIMIT_VAR))
|
||
{
|
||
sprintf(buffer, "\"%s\"", fn->filename);
|
||
ptr = (pack *)alloca(sizeof(pack));
|
||
memset(ptr, 0, sizeof(pack));
|
||
ptr->file = LOCAL_COPY(buffer);
|
||
ptr->desc = LOCAL_COPY(buffer);
|
||
ptr->numfiles = 1;
|
||
ptr->size = fn->filesize;
|
||
ptr->server = from_server;
|
||
do_hook(MODULE_LIST, "FS: Queue Add %s %s", nick, buffer);
|
||
|
||
if (add_to_queue(nick, "SEND", ptr))
|
||
{
|
||
statistics.files_served++;
|
||
statistics.filesize_served += fn->filesize;
|
||
}
|
||
else if (do_hook(MODULE_LIST, "FS: QueueFile %s %s", nick, buffer))
|
||
queue_send_to_server(from_server, "PRIVMSG %s :Queued File %s", nick, buffer);
|
||
} else if (do_hook(MODULE_LIST, "FS: Queue Full %s", nick))
|
||
queue_send_to_server(from_server, "PRIVMSG %s :Queue is full, try again later.", nick);
|
||
}
|
||
else
|
||
{
|
||
dcc_filesend("SEND", buffer);
|
||
statistics.files_served++;
|
||
statistics.filesize_served += fn->filesize;
|
||
}
|
||
}
|
||
}
|
||
else if (!my_stricmp(get_server_nickname(from_server), command))
|
||
{
|
||
char *name = NULL;
|
||
if (fserv_filename || (name = make_temp_list(nick)))
|
||
{
|
||
sprintf(buffer, "%s %s", nick, fserv_filename ? fserv_filename : name);
|
||
dcc_filesend("SEND", buffer);
|
||
}
|
||
}
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
void impress_me(void *args)
|
||
{
|
||
int timer;
|
||
char *ch = NULL;
|
||
ChannelList *chan= NULL;
|
||
|
||
timer = get_dllint_var("fserv_time");
|
||
if (timer < DEFAULT_IMPRESS_TIME)
|
||
timer = DEFAULT_IMPRESS_TIME;
|
||
if (!(ch = get_dllstring_var("fserv_chan")) || !*ch)
|
||
ch = NULL;
|
||
else
|
||
ch = m_strdup(ch);
|
||
chan = get_server_channels(from_server);
|
||
if (!ch)
|
||
ch = m_strdup(get_current_channel_by_refnum(0));
|
||
else
|
||
{
|
||
char *c,
|
||
*p;
|
||
|
||
c = LOCAL_COPY(ch);
|
||
ch = NULL;
|
||
if (*c == '*')
|
||
{
|
||
ChannelList *chan;
|
||
for (chan = get_server_channels(from_server); chan; chan=chan->next)
|
||
m_s3cat(&ch, ",", chan->channel);
|
||
}
|
||
else
|
||
{
|
||
ChannelList *tmpchan;
|
||
while ((p = next_in_comma_list(c, &c)) && *p)
|
||
{
|
||
if ((tmpchan = (ChannelList *)find_in_list((List **)&chan, p, 0)))
|
||
m_s3cat(&ch, ",", p);
|
||
}
|
||
}
|
||
}
|
||
if (fserv_files && get_dllint_var("fserv_impress"))
|
||
{
|
||
unsigned long l;
|
||
Files *new;
|
||
|
||
l = random_number(0L) % statistics.total_files;
|
||
for (new = fserv_files; new && l; new = new->next, l--)
|
||
;
|
||
if (new && new->bitrate)
|
||
{
|
||
char frq[30],
|
||
size[40],
|
||
*p;
|
||
p = strrchr(new->filename, '/');
|
||
p++;
|
||
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))
|
||
{
|
||
sprintf(frq, "%3.1f", ((double)new->freq)/1000.0);
|
||
sprintf(size, "%4.3f%s", _GMKv(new->filesize), _GMKs(new->filesize));
|
||
queue_send_to_server(from_server, "PRIVMSG %s :[ !%s %s ] [%s %uKbps %sKhz %s]-[%s]",
|
||
ch, get_server_nickname(from_server), p,
|
||
size, new->bitrate, frq,
|
||
mode_str(new->stereo),
|
||
print_time(new->time));
|
||
}
|
||
}
|
||
}
|
||
add_timer(0, empty_string, timer * 1000, 1, impress_me, NULL, NULL, -1, "fserv");
|
||
new_free(&ch);
|
||
}
|
||
|
||
BUILT_IN_FUNCTION(func_convert_mp3time)
|
||
{
|
||
int hours,
|
||
minutes,
|
||
seconds;
|
||
if (!input)
|
||
return m_strdup(empty_string);
|
||
seconds = my_atol(input);
|
||
hours = seconds / ( 60 * 60 );
|
||
minutes = seconds / 60;
|
||
seconds = seconds % 60;
|
||
return m_sprintf("[%02d:%02d:%02d]", hours, minutes, seconds);
|
||
}
|
||
|
||
BUILT_IN_DLL(stats_fserv)
|
||
{
|
||
put_it("%s\t File Server Statistics From %s", FSstr, my_ctime(statistics.starttime));
|
||
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"));
|
||
put_it("%s\t Files available %lu for %4.3f%s",FSstr, statistics.total_files, _GMKv(statistics.total_filesize), _GMKs(statistics.total_filesize));
|
||
put_it("%s\t Files served %lu for %4.3f%s", FSstr, statistics.files_served, _GMKv(statistics.filesize_served), _GMKs(statistics.filesize_served));
|
||
}
|
||
|
||
|
||
|
||
BUILT_IN_DLL(save_fserv)
|
||
{
|
||
char bogus[] = "fserv";
|
||
FILE *fp;
|
||
char buffer[BIG_BUFFER_SIZE];
|
||
char *p;
|
||
char *fserv_savname = NULL;
|
||
sprintf(buffer, "%s/fserv.sav", get_string_var(CTOOLZ_DIR_VAR));
|
||
fserv_savname = expand_twiddle(buffer);
|
||
if (!(fp = fopen(fserv_savname, "w")))
|
||
{
|
||
new_free(&fserv_savname);
|
||
return;
|
||
}
|
||
fprintf(fp, "%s %s\n", bogus, on_off(get_dllint_var("fserv")));
|
||
if ((p = get_dllstring_var("fserv_dir")))
|
||
fprintf(fp, "%s%s %s\n", bogus, "_dir", p);
|
||
if ((p = get_dllstring_var("fserv_chan")))
|
||
fprintf(fp, "%s%s %s\n", bogus, "_chan", p);
|
||
if ((p = get_dllstring_var("fserv_filename")))
|
||
fprintf(fp, "%s%s %s\n", bogus, "_filename", p);
|
||
if ((p = get_dllstring_var("fserv_format")))
|
||
fprintf(fp, "%s%s %s\n", bogus, "_format", p);
|
||
fprintf(fp, "%s%s %u\n", bogus, "_time", get_dllint_var("fserv_time"));
|
||
fprintf(fp, "%s%s %u\n", bogus, "_max_match", get_dllint_var("fserv_max_match"));
|
||
fprintf(fp, "%s%s %s\n", bogus, "_impress", on_off(get_dllint_var("fserv_impress")));
|
||
if (statistics.files_served)
|
||
{
|
||
fprintf(fp, "%s%s %lu\n", bogus, "_totalserved", statistics.files_served);
|
||
fprintf(fp, "%s%s %lu\n", bogus, "_totalstart", statistics.starttime);
|
||
fprintf(fp, "%s%s %lu\n", bogus, "_totalsizeserved", statistics.filesize_served);
|
||
}
|
||
fclose(fp);
|
||
if ((do_hook(MODULE_LIST, "FS: Save")))
|
||
put_it("%s Done Saving.", FSstr);
|
||
new_free(&fserv_savname);
|
||
}
|
||
|
||
void fserv_read(char *filename)
|
||
{
|
||
FILE *fp;
|
||
char buff[IRCD_BUFFER_SIZE+1];
|
||
char *fserv_savname = NULL;
|
||
fserv_savname = expand_twiddle(filename);
|
||
if (!(fp = fopen(fserv_savname, "r")))
|
||
{
|
||
new_free(&fserv_savname);
|
||
return;
|
||
}
|
||
fgets(buff, IRCD_BUFFER_SIZE, fp);
|
||
while (!feof(fp))
|
||
{
|
||
char *p;
|
||
chop(buff, 1);
|
||
if ((p = strchr(buff, ' ')))
|
||
{
|
||
*p++ = 0;
|
||
|
||
if (!my_strnicmp(buff, "fserv_totalserved", 17))
|
||
statistics.files_served = strtoul(p, NULL, 0);
|
||
else if (!my_strnicmp(buff, "fserv_totalsizeserved", 17))
|
||
statistics.filesize_served = strtoul(p, NULL, 0);
|
||
else if (!my_strnicmp(buff, "fserv_totalserved", 17))
|
||
statistics.starttime = strtoul(p, NULL, 0);
|
||
else
|
||
{
|
||
if (*p > '0' && *p < '9')
|
||
{
|
||
int val;
|
||
val = my_atol(p);
|
||
set_dllint_var(buff, val);
|
||
}
|
||
else if (!my_stricmp(p, "ON"))
|
||
set_dllint_var(buff, 1);
|
||
else if (!my_stricmp(p, "OFF"))
|
||
set_dllint_var(buff, 0);
|
||
else
|
||
set_dllstring_var(buff, p);
|
||
}
|
||
}
|
||
fgets(buff, IRCD_BUFFER_SIZE, fp);
|
||
}
|
||
fclose(fp);
|
||
}
|
||
|
||
BUILT_IN_DLL(help_fserv)
|
||
{
|
||
put_it("%s FServ %s by Colten Edwards aka panasync", FSstr, AUTO_VERSION);
|
||
put_it("%s [Sets]", FSstr);
|
||
put_it("%s fserv on/off fserv functions. Default is %s", FSstr, on_off(DEFAULT_FSERV));
|
||
put_it("%s fserv_dir path [path]", FSstr);
|
||
put_it("%s fserv_chan #chan[,#chan2]", FSstr);
|
||
put_it("%s fserv_time seconds between displays of random mp3. Default is %d", FSstr, DEFAULT_IMPRESS_TIME);
|
||
put_it("%s fserv_max_match defines how many matches allowed. Default is %d", FSstr, DEFAULT_MAX_MATCH);
|
||
put_it("%s fserv_impress on/off public display of random mp3. Default is %s", FSstr, on_off(DEFAULT_IMPRESS));
|
||
put_it("%s", FSstr);
|
||
put_it("%s channel commands are @find pattern or @locate pattern", FSstr);
|
||
put_it("%s !nick filename to send a file to nick requesting", FSstr);
|
||
put_it("%s a /msg to the nick can be used instead of a public", FSstr);
|
||
put_it("%s a $mp3time() function as well as a hook are provided. /on module \"FS:*\"", FSstr);
|
||
put_it("%s more help available with /help", FSstr);
|
||
}
|
||
|
||
int Fserv_Lock(IrcCommandDll **intp, Function_ptr *global_table)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
char *Fserv_Version(IrcCommandDll **intp)
|
||
{
|
||
return AUTO_VERSION;
|
||
}
|
||
|
||
|
||
int Fserv_Init(IrcCommandDll **intp, Function_ptr *global_table)
|
||
{
|
||
char buffer[BIG_BUFFER_SIZE+1];
|
||
initialize_module("Fserv");
|
||
add_module_proc(VAR_PROC, "Fserv", "fserv", NULL, BOOL_TYPE_VAR, DEFAULT_FSERV, NULL, NULL);
|
||
add_module_proc(VAR_PROC, "Fserv", "fserv_dir", NULL, STR_TYPE_VAR, 0, NULL, NULL);
|
||
add_module_proc(VAR_PROC, "Fserv", "fserv_chan", NULL, STR_TYPE_VAR, 0, NULL, NULL);
|
||
add_module_proc(VAR_PROC, "Fserv", "fserv_filename", NULL, STR_TYPE_VAR, 0, NULL, NULL);
|
||
add_module_proc(VAR_PROC, "Fserv", "fserv_format", NULL, STR_TYPE_VAR, 0, NULL, NULL);
|
||
add_module_proc(VAR_PROC, "Fserv", "fserv_time", NULL, INT_TYPE_VAR, DEFAULT_IMPRESS_TIME, NULL, NULL);
|
||
add_module_proc(VAR_PROC, "Fserv", "fserv_max_match", NULL, INT_TYPE_VAR, DEFAULT_MAX_MATCH, NULL, NULL);
|
||
add_module_proc(VAR_PROC, "Fserv", "fserv_impress", NULL, BOOL_TYPE_VAR, DEFAULT_IMPRESS, NULL, NULL);
|
||
|
||
sprintf(buffer, " [-recurse] [path [path]] to load all files -recurse is a \ntoggle and can appear anywhere. Default is [%s]", on_off(DEFAULT_RECURSE));
|
||
add_module_proc(COMMAND_PROC, "Fserv", "fsload", NULL, 0, 0, load_fserv, buffer);
|
||
|
||
sprintf(buffer, " [-count #] [-freq #] [-bitrate #] [pattern] to search database locally");
|
||
add_module_proc(COMMAND_PROC, "Fserv", "fsprint", NULL, 0, 0, print_fserv, buffer);
|
||
|
||
sprintf(buffer, " to remove all files or [pat [pat]] to remove specific");
|
||
add_module_proc(COMMAND_PROC, "Fserv", "fsunload", NULL, 0, 0, unload_fserv, buffer);
|
||
|
||
add_module_proc(COMMAND_PROC, "Fserv", "fshelp", NULL, 0, 0, help_fserv, " to provide help for fserv plugin");
|
||
|
||
sprintf(buffer, " [-recurse] [path [path]] to reload all files");
|
||
add_module_proc(COMMAND_PROC, "Fserv", "fsreload", NULL, 0, 0, load_fserv, buffer);
|
||
|
||
add_module_proc(COMMAND_PROC, "Fserv", "fsstats", NULL, 0, 0, stats_fserv, " provides fserv statistics");
|
||
|
||
sprintf(buffer, " Creates list of mp3");
|
||
add_module_proc(COMMAND_PROC, "Fserv", "fslist", NULL, 0, 0, list_fserv, buffer);
|
||
|
||
sprintf(buffer, " to save your stats and settings to %s/fserv.sav", get_string_var(CTOOLZ_DIR_VAR));
|
||
add_module_proc(COMMAND_PROC, "Fserv", "fssave", NULL, 0, 0, save_fserv, buffer);
|
||
|
||
|
||
add_module_proc(ALIAS_PROC, "Fserv", "mp3time", NULL, 0, 0, func_convert_mp3time, NULL);
|
||
add_module_proc(HOOK_PROC, "Fserv", NULL, "*", PUBLIC_LIST, 1, NULL, search_proc);
|
||
add_module_proc(HOOK_PROC, "Fserv", NULL, "*", MSG_LIST, 1, NULL, search_proc);
|
||
add_module_proc(HOOK_PROC, "Fserv", NULL, "*", PUBLIC_OTHER_LIST, 1, NULL, search_proc);
|
||
|
||
add_completion_type("fsload", 3, FILE_COMPLETION);
|
||
|
||
add_timer(0, empty_string, get_dllint_var("fserv_time"), 1, impress_me, NULL, NULL, -1, "fserv");
|
||
strmcpy(FSstr, cparse(FS, NULL, NULL), sizeof(FSstr) - 1);
|
||
put_it("%s %s", FSstr, convert_output_format("$0 v$1 by panasync.", "%s %s", fserv_version, AUTO_VERSION));
|
||
sprintf(buffer, "$0+%s by panasync - $2 $3", fserv_version);
|
||
fset_string_var(FORMAT_VERSION_FSET, buffer);
|
||
statistics.starttime = time(NULL);
|
||
|
||
sprintf(buffer, "%s/fserv.sav", get_string_var(CTOOLZ_DIR_VAR));
|
||
fserv_read(buffer);
|
||
|
||
put_it("%s for help with this fserv, /fshelp", FSstr);
|
||
return 0;
|
||
}
|
||
|