
/*
Todo:
  Install cgi on netwinsite.com
  Test with news server on netwinsite.com


update=3600
freq=10% file=ad1.txt,ad2.txt groups=rec.*,alt.*,!*usenet*
freq=20% file=ad4.txt groups=comp.*
freq=30% file=rec.txt groups=rec.*
freq=10% file=rec.txt groups=rec.humor

*/



#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include "emsg.h"
#include "str.h"
#include "cmd.h"
#include "sary.h"
#include "group.h"
#include "dnews.h"
#include "lib.h"
#include "item.h"
#include "chan.h"
#include "hist.h"
#include "expire.h"
#include "feed.h"
#include "post.h"
#include "suck.h"
#include "chan_dmy.h"
#include "db.h"
#include "nntp.h"

#include "sponser.h"
#undef mymalloc
#undef myfree
#define mymalloc(x) mymalloc2(x,M_TOMAIL)
#define myfree(x) myfree2(x,M_TOMAIL)


#ifdef OS2
#define vsnprintf _vbprintf
#endif
int sponser_setused(char *fname, int x);

char *file_sponser(char *fname);
char *sponser_find(char *group);
int sponser_report(char *url);
int sponser_append(String *msg);
void sponser_config_line(char *xin);
int sponser_add(double freq, char *file, char *groups);
void sponser_free(void);
int sponser_spliturl(char *url, char *site, char *fullpath, char *path);
int sponser_fetch_file(char *url, char *lcl);
int sponser_fetch(char *url);
int sponser_fetch_afile(char *url, char *fname);
static int sponser_disable;
static int cur_date;
static int last_fetch;
static int fetch_delay=60*60*24*7; /* default to fetch once a week */ 
static int sponser_percent=100; /* default to sponsering all messages */
#define PERIOD_DAY (60*60*24)
#define PERIOD_YEAR (60*60*24*365)
#define FILE_USED file_work("sponser.use")
#define FILE_SPONSER file_work("sponser.dat")
#define FILE_REMOTE file_work("sponser.rmt")
void sponser_read_config(void)
{
	FILE *f;
	char bf[BFSZ];
	int nused;
	char fname[BFSZ];
	char *s;
	cur_date = lib_cdate(FILE_SPONSER);
	sponser_free();
	f = fopen(FILE_SPONSER,"r");
	if (f==NULL) {
		return;
	}
	for (;!feof(f);) {
		if (fgets(bf,BFSZ-1,f)==NULL) break;
		s = strchr(bf,'\n'); if (s!=NULL) *s = 0;
		sponser_config_line(bf);
	}
	fclosep(f);
	f = fopen(FILE_USED,"r");
	if (f==NULL) {
		return;
	}
	for (;!feof(f);) {
		if (fgets(bf,BFSZ-1,f)==NULL) break;
		s = strchr(bf,'\n'); if (s!=NULL) *s = 0;
		s = strtok(bf," \r\n"); if (s==NULL) continue;
		ncpy(fname,s,200);
		s = strtok(NULL," \r\n"); if (s==NULL) continue;
		nused = atoi(s);
		sponser_setused(fname,nused);
	}
	fclosep(f);
}
/*
	freq=10% file=rec.txt groups=rec.humor
*/

void sponser_config_line(char *xin)
{
	char *p[100];
	int n;
	int i;
	char freq[BFSZ];
	char file[BFSZ];
	char groups[BFSZ];

	strcpy(freq,"");
	strcpy(file,"");
	strcpy(groups,"");
	n = token_quote(xin,p,99);
	for (i=0; i<n; i++) {
		if (strcmp(p[i],"freq")==0) {
			if (i+2>=n) {emsg("Parameters missing in %s %s\n",FILE_SPONSER,p[i]); return;}
			i++;
			ncpy(freq,p[++i],BFSZ-1); 
		} else if (strcmp(p[i],"file")==0) {
			if (i+2>=n) {emsg("Parameters missing in %s %s\n",FILE_SPONSER,p[i]); return;}
			i++;
			ncpy(file,p[++i],BFSZ-1); 
		} else if (strcmp(p[i],"groups")==0) {
			if (i+2>=n) {emsg("Parameters missing in %s %s\n",FILE_SPONSER,p[i]); return;}
			i++;
			ncpy(groups,p[++i],BFSZ-1); 
		} else if (strcmp(p[i],"update")==0) {
			if (i+2>=n) {emsg("Parameters missing in %s %s\n",FILE_SPONSER,p[i]); return;}
			i++;
			fetch_delay = atoi(p[++i]);
			if (fetch_delay < PERIOD_DAY) fetch_delay = PERIOD_DAY;
			if (fetch_delay > PERIOD_YEAR) fetch_delay = PERIOD_YEAR;
			dmsg("sponser: update = %d = %d minutes\n",fetch_delay,fetch_delay/60);
			return;
		}
		else if (strcmp(p[i],"sponser")==0) {
			if (i+2>=n) {emsg("Parameters missing in %s %s\n",FILE_SPONSER,p[i]); return;}
			i++;
			sponser_percent = atoi(p[++i]);
			if (sponser_percent < 0) sponser_percent=0;
			if (sponser_percent > 100) sponser_percent=100;
			dmsg("sponser: sponser percentage = %d\n",sponser_percent);
			return;
		} else {
			emsg("Unknown setting in %s (%s)\n",FILE_SPONSER,p[i]);
		}
	}
	if (strlen(file)>0) if (strlen(groups)>0) 
		sponser_add(atof(freq),file,groups);
}
typedef struct RULE {double freq; char *file; char *groups; struct RULE *next; int nused; int matches;} Rule;
static Rule *rules;
void sponser_free(void)
{
	Rule *r,*rnext;
	for (r=rules;r!=NULL;r=rnext) {
		rnext = r->next;
		mystrfree(r->file,M_TOMAIL);
		mystrfree(r->groups,M_TOMAIL);
		myfree(r);
	}
	rules = NULL;
}
int sponser_add(double freq, char *file, char *groups)
{
	Rule **next;
	Rule *r;
	next = &rules;
	if (file==NULL) return FALSE;
	if (groups==NULL) return FALSE;
	if (strlen(file)==0) return FALSE;
	if (strlen(groups)==0) return FALSE;

	dmsg("sponser: add rule %g (%s) (%s)\n",freq,file,groups);
	for (r=rules;r!=NULL;r=r->next) next = &r->next;
	r = mymalloc(sizeof(Rule));
	memset(r,0,sizeof(Rule));
	r->freq = freq;
	r->file = mystrdup(file,M_TOMAIL);
	r->groups = mystrdup(groups,M_TOMAIL);
	r->nused = 0 ;
	*next = r;
	return TRUE;
}
int sponser_write(void)
{
	Rule *r;
	FILE *f;
	f = fopen(FILE_USED,"w");
	if (f==NULL) return FALSE;
	for (r=rules;r!=NULL;r=r->next) {
		fprintf(f,"%s %d\n",r->file,r->nused);
	}
	fclose(f);
	return TRUE;	
}
char *sponser_find(char *group)
{
	static int x;
	Rule *r;
	int nmatch=0;
	int pickone;
	int i;
	static int done=FALSE;

	if (!done) {srand(time(NULL)); done=TRUE; }
	for (r=rules;r!=NULL;r=r->next) {
		r->matches=group_match(r->groups,group);
		if (r->matches) nmatch++;
	}
	if (nmatch==0) {
		dmsg("sponser_find: no rules matched for group '%.200s'\n",group);
		return NULL;
	}
	if (!((abs(rand()%1000)) < (sponser_percent*10))) {
		dmsg("sponser_find: not attaching message due to sponser percentage limit\n");
		return NULL;
	}
	if (nmatch>1) {
		for(i=0;i<10;i++) {
			pickone=(abs(rand()%nmatch))+1;
			x=0;
			for (r=rules;r!=NULL;r=r->next) {
				if (r->matches) {
					x++;
					if (x==pickone) break;
				}
			}
			if ((abs(rand()%1000)) < (r->freq*10) ) {
				dmsg("sponser_find: using rule %d of %d rules matching group '%.200s'\n",x,nmatch,group);
				r->nused++ ;
				sponser_write();
				return r->file;	
			}			
		}
		dmsg("sponser_find: too many iterations, just gonna use this one!\n");
	} else {
		for (r=rules;r!=NULL;r=r->next) if (r->matches) break;
	}
	r->nused++ ;
	sponser_write();
	return r->file;	

	/*
	for (r=rules;r!=NULL;r=r->next) {
		imsg("sponser_find: group_match(%.200s,%.200s)\n",r->groups,group);
		if (group_match(r->groups,group)) {
			imsg("sponser_find: group_matched!\n");
			if ( (abs(rand()%1000)) < (r->freq*10) ) {
				imsg("sponsor_find: using this one!\n");
				r->nused++ ;
				sponser_write();
				return r->file;	
			}			
		}
	}*/
	return NULL;
}
int sponser_setused(char *fname, int x)
{
	Rule *r;
	for (r=rules;r!=NULL;r=r->next) {
		if (strcmp(r->file,fname)==0) {
			r->nused = x;
			break;
		}
	}
	return TRUE;
}
int sponser_append(String *msg)
{
	/*	Chose message and add it if necessary etc also
		check if running in sponser mode ... 
	*/
	FILE *f;
	char bf[BFSZ];
	char groups[BFSZ];
	char *fname;
	char *s;

	if (sponser_disable) {
    	    dmsg("sponser: disable was true \n");
	    return FALSE;
	}
	dmsg("sponser: checking \n");
	ncpy(groups,get_ahead(msg,"Newsgroups:"),BFSZ-10);
	strlwr(groups);
	s = strchr(groups,','); if (s!=NULL) *s = 0;

	s = strstr(str_s(msg),"----------");
	if (s!=NULL) {
		if (config_true(C_SPONSER_NICER)) {
			dmsg("sponser: Not appending sponser message as ----- found in message\n");
			return FALSE;
		}
	}
	s = strstr(str_s(msg),"-+");
	if (s!=NULL) {
		dmsg("sponser: Not appending sponser message as -+ found in message\n");
		return FALSE;
	}

	fname = sponser_find(groups);
	if (fname==NULL) return FALSE;
	imsg("sponser: adding (%s) to post in group (%.100s) \n",fname,groups);
	f = fopen(file_sponser(fname),"r");
	if (f==NULL) {
		imsg("Unable to open (%s)\n",file_sponser(fname));
		return FALSE;
	}
	for (;!feof(f);) {
	 	if (fgets(bf,BFSZ-10,f)==NULL) break;
		s = strchr(bf,'\n');
		if (s!=NULL) *s = 0;
		if (strcmp(bf,".")==0) strcpy(bf,"..");
		strcat(bf,"\015\012");
		str_addsn(msg,bf);
	}
	fclosep(f);
	return TRUE;
}
char *file_sponser(char *fname)
{
        char bf[BFSZ];
#ifdef VMS
        lprintf(bf,BFSZ-1,"sponser_%s",fname);
#else
        lprintf(bf,BFSZ-1,"sponser/%s",fname);
#endif
        return file_work(bf);
}
int sponser_spliturl(char *url, char *site, char *fullpath, char *path)
{
	/* Fetch sponser.dat from the specified url http://site/path/sponser.dat */
	/* Load it in, then fetch the files it references */
	char *s;
	char *last;
	s = strstr(url,"//");
	if (s==NULL) {
badurl:		imsg("Invalid url (%s)\n",url);
		return FALSE;
	}
	ncpy(site,s+2,200);
	s = strstr(site,"/"); if (s==NULL) goto badurl;
	ncpy(fullpath,s,200);
	ncpy(path,fullpath,200);
	*s = 0;
	for (s=path;*s!=0;s++) if (*s=='/') last = s;
	if (last==NULL) goto badurl;
	last[1] = 0;
	return TRUE;		
}
/*
Current root directory (d:\surgeftp)
Request: GET /cgi/surgeftpmgr.cgi?cmd=domain&domain=2 HTTP/1.0
Referer: http://orion:7021/
Connection: Keep-Alive
User-Agent: Mozilla/4.7 [en] (WinNT; I)
Pragma: no-cache
Host: orion:7021
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg...
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8

*/
int sponser_fetch_file(char *url, char *lcl)
{
	/* Fetch sponser.dat from the specified url http://site/path/sponser.dat */
	/* Load it in, then fetch the files it references */
	char site[BFSZ];
	char fullpath[BFSZ];
	char path[BFSZ];
	char bf[BFSZ];
	char tmp[BFSZ];
	int chan;
	int code;
	char reason[BFSZ];
	char *s;
	int xat;
	int r;
	int ret=FALSE;
	String *str=NULL;
	FILE *f=NULL;
	if (!sponser_spliturl(url,site,fullpath,path)) return FALSE;
	strcat(site,":80");
	dmsg("sponser: open (%s) (%s) (%s)\n",site,url,lcl);
	chan = nntp_open(site);
	if (chan<0) {
		dmsg("sponser: Unable to open sponser link (%s) not serious\n",site);
		return FALSE;
	}
	if (!nntp_wait_write(chan,10000)) {
		/* Give up after 10 seconds */	
		imsg("sponser: Connect timed out, ignore this\n");
		goto failed;
	}
	lprintf(bf,BFSZ-1,"GET %s HTTP/1.0\r\n",fullpath);
	dmsg("sponser: sending (GET %s HTTP/1.0)\n",fullpath);
	lprintf(tmp,BFSZ-1,"Host: %s\r\n\r\n",site); strcat(bf,tmp);
/*	strcat(bf,"Content-Length: 0\r\n\r\n\r\n");*/

	r = nntp_socket_write(chan,bf,strlen(bf));
	if (r<(int) strlen(bf)) {
		imsg("sponser: write failed\n");
		goto failed;
	}
	lib_createdir(lcl); 
	f = fopen(lcl,"w");
	if (f==NULL) {
		imsg("sponser: Unable to write (%s)\n",lcl);
		goto failed;
	}

	str = str_new();
	for (;TRUE;) {
		r = nntp_read_timed(chan,bf,BFSZ-1,1000*10,reason); /* Wait upto 20 seconds */
		if (r<=0) {
			break;
		}
		str_adds(str,bf,r);
	}

	xat = 0;
	s = str_line_next(str,&xat);
	code = 0;
	if (s!=NULL) if (strlen(s)>9) {
		/* HTTP/1.0 404 Object Not Found */
		dmsg("sponser: Status (%.200s)\n",s);
		code = atoi(s+9);
	}
	if (code>300 || code==0) {
		if (s!=NULL) imsg("sponser: Could not retrieve file (%s)\n",s);
		goto failed;
	}
	for (;s!=NULL;s=str_line_next(str,&xat)) {
		/*imsg("data (%s)\n",s);*/
		if (strcmp(s,"")==0) break; 
	}
	if (s!=NULL) s = str_line_next(str,&xat); /* throw away the blank line */
	for (;s!=NULL;s=str_line_next(str,&xat)) {
		/*imsg("data2 (%s)\n",s);*/
		fprintf(f,"%s\n",s);
	}
	ret = TRUE;
failed:
	if (f!=NULL) fclose(f);
	if (chan>=0) nntp_doclose(chan);
	if (str!=NULL) str_free(str);
	dmsg("sponser: Finished fetch file\n");
	return ret;
}
int sponser_fetch(char *url)
{
	int v;
	Rule *r;
	char fname[BFSZ];
	strcpy(fname,FILE_REMOTE);

	if (last_fetch==0) sponser_read_config(); /* to get fetch_delay if it's non standard*/
	if (last_fetch==0) last_fetch = lib_cdate(FILE_SPONSER);

	if ((lib_gmtime() - last_fetch) < fetch_delay) return TRUE;
	dmsg("sponser: last fetched %d seconds ago, fetch every %d seconds\n",(lib_gmtime() - last_fetch),fetch_delay);
	last_fetch = lib_gmtime();

	v = sponser_fetch_file(url,fname);
	if (!v) return FALSE;
	strcpy(fname,FILE_REMOTE);
	if (!lib_file_copy(fname,FILE_SPONSER)) return FALSE;
	sponser_read_config();
	sponser_report(url);
	for (r=rules;r!=NULL;r=r->next) {
		if (!sponser_fetch_afile(url,r->file)) return FALSE;	
	}
	return TRUE;
}
int sponser_report(char *url)
{
	char site[BFSZ];
	char fullpath[BFSZ];
	char reason[BFSZ];
	char path[BFSZ];
	int chan;
	char bf[20000];
	char tmp[BFSZ];
	char body[10000];
	int ret=FALSE;
	String *str=NULL;
	FILE *f=NULL;
	int i;
	int n;
	Rule *r;
	int gotsome=FALSE;

	for (i=0,r=rules;r!=NULL;r=r->next,i++) if (r->nused>0) gotsome = TRUE;
	if (!gotsome) {
		dmsg("sponser: Nothing to report\n");
		return TRUE;	
	}
	
	
	if (!sponser_spliturl(url,site,fullpath,path)) return FALSE;

	strcat(site,":80");
	chan = nntp_open(site);
	if (chan<0) {
		dmsg("sponser: Unable to open sponser link (%s) not serious\n",site);
		return FALSE;
	}
	if (!nntp_wait_write(chan,10000)) {
		/* Give up after 10 seconds */	
		dmsg("sponser: timedout\n");
		goto failed;
	}
	
	strcpy(body,"");
	for (i=0,r=rules;r!=NULL;r=r->next,i++) {
		lprintf(bf,200,"fname_%d=%s&used_%d=%d&",i,r->file,i,r->nused);
		strcat(body,bf);
		r->nused = 0;
		if (strlen(body)>5000) break;
	}
	sponser_write();
	lprintf(bf,200,"info=%s+%s&",host_details(),config_get(C_MANAGER));
	strcat(body,bf);
	lprintf(bf,200,"nfiles=%d&eom\r\n",i);
	strcat(body,bf);

	lprintf(bf,BFSZ-1,"POST /scripts/sponser.exe HTTP/1.0\r\n");
	lprintf(tmp,BFSZ-1,"Content-Type: application/x-www-form-urlencoded\r\n"); strcat(bf,tmp);
	strcat(bf,"Pragma: no-cache\r\n");
	lprintf(tmp,BFSZ-1,"Host: %s\r\n",site); strcat(bf,tmp);
	lprintf(tmp,100,"Content-Length: %d\r\n\r\n",strlen(body)); strcat(bf,tmp);

	strcat(bf,body);
	strcat(bf,"\r\n");

	n = nntp_socket_write(chan,bf,strlen(bf));
	if (n<(int) strlen(bf)) {
		imsg("sponser: write failed\n");
		goto failed;
	}
	for (;TRUE;) {
		n = nntp_read_timed(chan,bf,BFSZ-1,1000*10,reason); /* Wait upto 20 seconds */
		if (n<=0) break;
		bf[n] = 0;
	}

	ret = TRUE;
	dmsg("sponser: report completed\n");
failed:
	dmsg("sponser: report completed2\n");
	if (f!=NULL) fclose(f);
	if (chan>=0) nntp_doclose(chan);
	if (str!=NULL) str_free(str);
	return ret;


}
int sponser_fetch_afile(char *url, char *fname)
{
	char site[BFSZ];
	char fullpath[BFSZ];
	char path[BFSZ];
	char rmt[BFSZ];
	char lcl[BFSZ];
	if (!sponser_spliturl(url,site,fullpath,path)) return FALSE;

	dmsg("sponser: getafile (%s) (%s) \n",url,fname);
	lprintf(rmt,BFSZ-1,"http://%s%s%s",site,path,fname);
	strcpy(lcl,file_sponser(fname));
	return sponser_fetch_file(rmt,lcl);
}
static int is_free;
void sponser_init(void)
{
	char url[BFSZ];
	int r;
	static int done;
	if (sponser_disable) return;
	if (config_true(C_SPONSER_ENABLE)) {
		is_free = TRUE;		
	}
	if (!is_free) {
		imsg("sponser: Sponsor mode not enabled as not a free or sponser mode key\n");
		sponser_disable = TRUE;
		return;
	}
	if (config_true(C_SPONSER_DISABLE)) {
		sponser_disable = TRUE;
		imsg("sponser: Sponsor mode currently disabled by sponser_disable setting in dnews.conf\n");
		return;
	}
	if (config_true(C_SPONSOR_DISABLE)) {
		sponser_disable = TRUE;
		imsg("sponser: Sponsor mode currently disabled by sponser_disable setting in dnews.conf\n");
		return;
	}
	if (!done) imsg("sponser: To disable add sponser_disable true to dnews.conf\n");
	done = TRUE;
	strcpy(url,config_get(C_SPONSER_URL));
/*	if (strlen(url)==0) strcpy(url,"http://www.netwinsite.com/sponser/index.txt");*/
	if (strlen(url)==0) strcpy(url,"http://www.netwinsite.com/sponsor/index_new.txt");
	if (strlen(url)==0) return;
	imsg("sponser: Sponsor enabled, fetching (%s)\n",url);
	r = sponser_fetch(url);
	if (!r) {
		imsg("sponser: Disabled due to failed fetch of sponser files\n");
		sponser_disable = TRUE;
	} else imsg("sponser: sponser fetch completed successfully.\n");
}
void sponser_enable_free(void)
{
	is_free = TRUE;
}
/*----------------


POST /cgi/surgeftpmgr.cgi HTTP/1.1

Content-Type: application/x-www-form-urlencoded

Accept-Encoding: gzip, deflate

User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; ICONZ IE5CD)

Host: trek:9090

Content-Length: 245

Connection: Keep-Alive

Authorization: Basic Y2hyaXNwOmNocmlzcG5ldA==



domainid=0&name=ally&email=chrisp@Netwin.co.nz&address=&deny=&deny_msg=Come+back+later%2C+I+have+a+headache&loginfails=5+failures&greetings=Kick+ass+FTP+here%2C+what+can+I+do+for+you%21&passwd_check=none&cmd_domain_save.x=50&cmd_domain_save.y=12



---------------------*/