/* Copyright (C) 1995 NetWin, New Zealand, All rights reserved. */
/*
define all form and query variables starting gl_ 
as template variables. 
  rcmd_catchup and logoff
  test if browse and search cause subscaribe to occur. 
    Document changes. ini settings etc.
Walk thru test
Test ecapsulated mime.
  ----  
Test with old templates
Add two functions to authenticaton


If first char of message is a capital M and if subject
contains (nn/nn) or [nn/nn] and if length greather than 10K 
then display it as an attachment.

IF 'getparts' then search xover for items with similar subject
minus the [] or () part, 
	Then fetch each message in order (if all found)
	Then store uu data to pid.tmp file
	decode it
	Send it to user.


*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#ifdef isunix
#include <unistd.h>
#endif
#ifdef WIN32
#include <windows.h>
#include <io.h>
#else
#include <signal.h>
#include <errno.h>
#endif
#ifdef OS2
#include <io.h>
#endif
#include <fcntl.h>
#include "dnews.h"
#include "conf.h"
#include "lib.h"
#include "emsg.h"
#include "nntp.h"
#ifndef TRUE
#define FALSE 0
#define TRUE (!FALSE)
#endif
static int docache=FALSE;
static int dodebug=FALSE;
/*
Commands that we need to support
        xover comp.os.vms [nnn-nnn]  Default is last 20 messages in group 
        article comp.os.vms nnn
        post message
        list comp.os.*                  Just show the ones at that level
*/
void display_info(char *epath);
char *decode_basic(char *rest);
char *rfc1522s(char *in);
char *cookie_date_plus(int tplus);
void tpl_show_latest(void);
void show_error(void);
char *pad_right(char *s, int n);
int decode_base64(char *buf, char *out);
void boundary_add(char *s);
int decode_uu(char *line, char *out);
static char tplname[BFSZ];
char *user_get(char *s);
void r_login(int nooutput);
void f_login(void);
void r_parts(void);
void r_user(void);

void cmd_tomail_add(void);
void cmd_tomail_del(void);
void cmd_tomail_add_thread(void);

void cmd_next(void);
void cmd_last(void);
void cmd_thread_next(void);
void cmd_thread_last(void);
void group_fetch(void);
void do_login(char *bf);
void f_config(void);
void r_config(void);
char *eoltospace(char *s);
int nntp_read_timeout(int c, char *bf, int sz);
static int done_content;
void do_content(void);
void r_xdebug(void);
char *get_line_head(String *instr);
char *either_find(char *s);
int parts_subject(char *subject, char *subj, char *fname, int *parti, int *partmax);

char *attach_fname(void);
char *attach_type(void);
char *attach_showname(void);
char *get_quote(char *s);
char *temp_fname(void);
int open_status(void);
void cgi_addvar(char *name, char *value);
void cmd_up(void);
void cmd_search_down(void);
void cmd_search_up(void);
char *get_cookie(char *var);

void cmd_down(void);
void cmd_latest(void);
void cmd_search(void);
void cmd_related(void);
static int isquery;
void get_line_clear(void);
void show_dline(char *s);
void r_logout(void);
void r_listall(void);
void netwin_advert(void);
void f_follow(int follow);
char *xstrtok(char *line, char *in);
char *towww(char *s);
void r_find(void);  /* from=nnn   max=nnn*/
void f_find(void);
void set_id(void);
void group_add(char *s);
void r_subscribe(void);
char *int_str(int i);
int xuser_clear(void);

void group_del(char *s);
void r_grpsearch(void);
void show_xsearch(void);
void f_search(void);
static int page_from;
static int page_to;
void r_search(void);
void tpl_show_item_image(void);
void f_post(void);
void h_printf(char * arg_list, ...);
int tcp_printf(int chan, char * arg_list,...);
void get_utag(char *ut);
void set_utag(char *user, char *dom);
void db_setscript(char *script);
int show_headfile(char *type, char *title);
void show_end(char *type);
int  show_top(char *type, char * arg_list, ...);
void show_article2(void);
char *lib_encode(char *s);
char *value_encode(char *s);
char *mygetenv(char *v);
char *query_find(char *s);
int query_get(void);
void getword(char *word, char *line, char stop, int len) ;
char x2c(char *what) ;
char *email_name(char *email);
void unescape_url(char *url) ;
void plustospace(char *str) ;
void tpl_quote_body(void);
int tpl_show_file(char *xfname);
char *file_tpl(char *fname);
int lib_file_length(char *fname);
void do_wrap(char *msg);
char *fix_crlf(char *msg);
void tpl_set_latest_vars(void);



int JLLgetindentlen(char *readpos);
int JLLgetindentonline(char *indent, char *readpos);
void JLLoutput(void (*outputfn)(char *), char *thisline);
int JLLprintword(char *readpos, char *indent, char *thisline, char *nextword, int wrap, int wordsfoundonline, void (*outputfn)(char *));
int JLLgetnextword(char *nextword, char *readpos);
char *JLLfindbeginningofline(char *readpos);
void JLLformat_wrap_output(void (*outputfn)(char *),char *readpos,int wrap);
int JLLmovereadposontonextword(char *readpos);
int JLLgetlenofnextline(char *readpos);

void JLLnntp_write_s(char *s);
void JLLcomment_write_s(char *s);
void JLLtext_encode(char *s);
int JLLchan;


#define xisspace(x) ((x==' ') || (x=='\t'))


char *tpl_replace(char *bf);
void tpl_init(void);
char *tpl_replace_vars(char *orig);
void tpl_replace_var(char *bf, int len, char *var);
void tpl_show_list(void);
char *cr_encode(char *s);
char *real_from(char *xin);
char *cr_decode(char *s);
void tpl_init_item(void);
void tpl_show_item(void);
void tpl_init_sbar(int from, int to, int total, char *key);
void user_set(char *var, char *val);
void show_text(char *s);
char *show_text_fn(char *s);

char *head_decode(char *s);
char *attach_justname(void);

void tpl_show_group(void);
void tpl_set_buttons(void);
void tpl_show(char *xfname);
void r_unsub(void);

void var_set(char *var, char *val);
char *var_find(char *var);


void show_sbar(int from, int to, int total, char *key);
void form_get(void);
char *form_find(char *s);
void show_article(void);
void show_raw(void);
int do_authent(void);

static int b_item= -1;
char *ref_encode(char *s);

static char path_script[BFSZ];
static char rootname[BFSZ];
int ini_read(char *s);
int ini_find(char *s);
char *ini_get(int x);
void r_post(void);
void r_catchup(void);
void zmsg(char * arg_list, ...);

void r_raw(void);
void r_article(void);
int read_lines(void);
int read_status(void);
int read_xover(void);
void show_xover(void);
void r_xover(void);  /* from=nnn   max=nnn*/
void r_list(void);
char *mygetenv(char *s);

static char ukey[BFSZ];

char *h_date_numeric(char *instr); 
char *h_date_trim(char *instr);
char *h_trim(char *s, int len);
char *h_from_trim(char *s);
#define MAX_ITEMS 4010


#ifdef WIN32
#define FIX_STDOUT TRUE
#endif

#ifdef OS2
#define FIX_STDOUT TRUE
#define _setmode setmode
#endif


void xover_add(char *item, char *subject, char *from, char *lines, char *date, char *mid, char *ref, char *bytes);
void xover_showord(void);
 
enum {I_HEADERS, I_XOVER_PRE, I_XOVER_POST, I_NEWSHOST, I_DEBUG, I_PAGESIZE
        , I_GROUPS, I_ALLOW, I_SORT, I_NOADVERT, I_SEARCH, I_CGI_PATH, I_TEMPLATES
        , I_POST_GROUPS, I_POST_USERS,I_LOG_FILE,I_SORT_REV,I_WRAP_POST,I_WRAP_TEXT
        , I_CONTENT_TYPE, I_ADD_MID, I_TELLNEWS_PASS, I_PRE_DISABLE
        , I_WORKAREA, I_POP_HOST, I_SORT_ORDER
        , I_AUTO_SUBSCRIBE
        , I_POST_DOMAIN
        , I_POST_REQUIRE_LOGIN
        , I_REQUIRE_LOGIN
        , I_WEB_LOGIN
        , I_POP_AUTHENT
        , I_LOGIN_TIMEOUT
        , I_ADD_BR
        , I_KEEP_FORMATING
        , I_POST_NOCACHE
        , I_SPACES
        , I_IGNORE_ADDRESS
	, I_FROM_IP
	, I_FROM_FORCE
	, I_REMOVE_NOCACHE
	, I_USER_CLEAR
	, I_GROUP_LIST
	, I_AUTH_NNTP
	, I_IGNORE_ID
	, I_FORMAT_HTML
	, I_LINK_ADD
	, I_NON_ASCII
	, I_USE_XACTIVE
	, I_DEFAULT_USER
	, I_POST_LOGIN
	, I_LATEST_PATH
	, I_FROM_NOCHECK
	, I_TOMAIL
	, I_DUMP
        , I_LATEST_IP
	, I_WEB_LOGIN_NOCHECK
	, I_ISTEXT_IMG
	, I_ISBINARY_IMG
	, I_ISBINARY_SIZE
	, I_USE_HOME
	, I_REMOVE_NAME
	, I_FROM_REMOTE_USER
	, I_FROM_OPTIONAL
        , I_SHOWINI
        , I_ALLOW_SCRIPT
        , I_ALLOW_FORM
        , I_ALLOW_JAVA
	, I_FROM_WEB_LOGIN
	, I_FROM_ALLOW_EMAIL
	, I_LOGIN_UTAG
	, I_LOGIN_COOKIE
	, I_SUBSCRIBE_MANUAL

};
char *ini_names[]={
        "headers","xover_pre","xover_post","newshost", "debug", "pagesize"
        ,"groups", "allow" , "sort", "noadvert", "search", "cgi_path"
        ,"templates" 
        ,"post_groups", "post_users","log_file"
        ,"sort_rev","wrap_post","wrap_text"
        ,"content_type", "add_mid", "tellnews_pass"
        ,"pre_disable", "workarea", "pop_host"
        ,"sort_order"
        ,"auto_subscribe"
        ,"post_domain"
        ,"post_require_login"
        ,"require_login"
        ,"web_login"
        ,"pop_authent"
        ,"login_timeout"
        ,"add_br"
        ,"keep_formating"
        ,"post_nocache"
        ,"spaces"
        ,"ignore_address"
	,"from_ip"
	,"from_force"
	,"remove_nocache"
	,"user_clear"
	,"group_list"
	,"auth_nntp"
	,"ignore_id"
	,"format_html"
	,"link_add"
	,"non_ascii"
	,"use_xactive"
	,"default_user"
	,"post_login"
	,"latest_path"
	,"from_nocheck"
	,"tomail"
	,"dump"
        ,"latest_ip"
	,"web_login_nocheck"
	,"istext_img"
	,"isbinary_img"
	,"isbinary_size"
	,"use_home"
	,"remove_name"
	,"from_remote_user"
	,"from_optional"
        ,"showini"
        ,"allow_script"
        ,"allow_form"
        ,"allow_java"
	,"from_web_login"
	,"from_allow_email"
	,"login_utag"
	,"login_cookie"
	,"subscribe_manual"
        , NULL
};
#define strdup d_strdup
#define PAGESIZE page_size()
char *content_type(void);
char *content_type(void)
{
        static char bf[BFSZ];
        strcpy(bf,ini_get(I_CONTENT_TYPE));
        if (strlen(bf)==0) strcpy(bf,"text/html");
        return bf;
}
char *d_strdup(const char *s);
char *d_strdup(const char *s)
{
        char *n = malloc(strlen(s)+1);
        strcpy(n,s);
        return n;
}
int page_size(void)
{
        int i = atoi(ini_get(I_PAGESIZE));
        if (i==0) i = 30;
        return i;
}
static char ltemplate[BFSZ];
static char auth_username[BFSZ]="";
static int body_lines;
static int items_per_group;
static int ngroups;
static int x_item[MAX_ITEMS];
static char *x_score[MAX_ITEMS];
static char *x_group[MAX_ITEMS];
static double x_f[MAX_ITEMS];
static int x_fi[MAX_ITEMS];
static int x_depth[MAX_ITEMS];
static char *x_subject[MAX_ITEMS];
static char *x_subjectsrt[MAX_ITEMS];
static char *x_from[MAX_ITEMS];
static char *x_date[MAX_ITEMS];
static char *x_ref[MAX_ITEMS];
static char *x_lines[MAX_ITEMS];
static char *x_bytes[MAX_ITEMS];
static char *x_mid[MAX_ITEMS];
static int nitem;

void emsg_reset(void);
static char guser[BFSZ]; /* chrisp */
static char utag[BFSZ]; /* chrisp domain */
static char udom[BFSZ];
static char utage[BFSZ]; /* chrisp+domain (encoded) */
static int chan;
static char thisuser[BFSZ];
static char thispass[BFSZ];
static char group[BFSZ];
static int gfrom,gto,gmax,group_from,group_to;
static int dosort;
static char log_file[BFSZ];
static int search_result = FALSE;
static int pre_disable=FALSE;
static char etext[10000];
static int format_html = FALSE;
#ifdef WIN32
#define environ _environ
#define putenv _putenv
#endif
#ifdef isunix
extern char **environ;
#endif

char *cookie_date(void);
static FILE *mystdin;
int main(int argc, char *argv[])
{
        char method[BFSZ];
	FILE *f;
        char cmd[BFSZ];
	int len;
	char *s;
	int nodump = FALSE;
#ifndef WIN32
        signal(SIGFPE,SIG_IGN);
#endif
	mystdin = stdin;
	if (argc==2) if (strcmp(argv[1],"-test")==0) {
		char bf[100000];
		/* get env from data.env, and re-assign stdin to be data.in  */
		f = fopen("dump.env","rb");
		for (;!feof(f);) {
			fgets(bf,90000,f);
			s = strchr(bf,'\n'); if (s!=NULL) *s = 0;
			putenv(bf);
		}
		fclose(f);
		len = atoi(mygetenv("CONTENT_LENGTH"));
		f = fopen("dump.in","rb");
		if (f!=NULL) {
			if (len>0) mystdin = f;
		}	
		nodump = TRUE;
	}


        strcpy(log_file,"dnewsweb.log");
        db_setscript(mygetenv("SCRIPT_NAME"));
        sprintf(log_file,"%s.log",rootname);
        if (!ini_read(argv[0])) return 0;
        if (strlen(ini_get(I_CGI_PATH))>0) {
                strcpy(path_script,ini_get(I_CGI_PATH));
        }
        if (strlen(ini_get(I_LOG_FILE))>0) {
                strcpy(log_file,ini_get(I_LOG_FILE));
        }
        
        if (strstr(ini_get(I_DEBUG),"true")!=NULL) dodebug = TRUE;
        if (!nodump) if (strstr(ini_get(I_DUMP),"true")!=NULL) {
		/* Dump environment variables and stdin to a file for debugging */	
		f = fopen("dump.env","wb");
		if (f!=NULL) {
			int i;
			for (i=0;environ[i]!=NULL;i++) {
				fprintf(f,"%s\n",environ[i]);
			}
			fclose(f);			
		}
		len = atoi(mygetenv("CONTENT_LENGTH"));
#ifdef FIX_STDOUT
		_setmode(_fileno(stdin),_O_BINARY);
#endif

		f = fopen("dump.in","wb");
		if (f!=NULL) {
			char bf[100000];
			int r;
			if (len>0) {
				r = fread(bf,1,len,stdin);
				fwrite(bf,1,r,f);
			}
			fclose(f);			
		}
		do_content();
		printf("Data dumped\n");
		exit(0);
	}
        if (strstr(ini_get(I_SORT),"true")!=NULL) dosort = TRUE;
        if (strcmp("true",ini_get(I_PRE_DISABLE))==0) pre_disable = TRUE;
        if (strcmp("true",ini_get(I_FORMAT_HTML))==0) {pre_disable = TRUE; format_html = TRUE;}
        if (!dodebug) emsg_reset();
	imsg("DNEWSWEB version %s\n",DNEWS_VERSION);
        imsg("DNEWSWEB, Startup, Looking for winsock dll\n");
        nntp_startup();
        nntp_alwaysblock();

        ncpy(thisuser,mygetenv("REMOTE_USER"),BFSZ-1);
	imsg("thisuser (%s)\n",thisuser);


	ncpy(thispass,mygetenv("AUTH_PASSWORD"),BFSZ-1); /* IIS apparently */
	if (strlen(thispass)==0) strcpy(thispass,decode_basic(mygetenv("HTTP_AUTHORIZATION")));
/*imsg("web_login (%s) (%s)\n",thisuser,thispass);*/
	if (strlen(thispass)>0) imsg("web_login got password user=%s ***\n",thisuser);
        ncpy(method,mygetenv("REQUEST_METHOD"),BFSZ-1); strlwr(method);
        query_get(); /* Get the xxx=yyy... parameters  */
	if (strcmp(method,"post")==0) {
		imsg("Processing POST\n");
                if (ini_true(I_POST_NOCACHE)) {
                        printf("Pragma: no-cache\n");
                        printf("Cache-Control: no-cache\n");
                        /*printf("Expires: Tue, 31 Dec 1996 23:59:59 GMT\n");*/
                }
                form_get(); /* get any form fields */

		if (!done_content) {
			if (docache) printf("Pragma: cache\n");
			done_content = TRUE;
			if (strcmp(form_find("cmd"),"login")==0) {
			  if (strlen(form_find("user"))>0) {
				printf("Set-Cookie: dnews_user=%s; expires=%s\n",form_find("user"),cookie_date());
			  }
			}
	                ncpy(cmd,form_find("cmd"),200);
                        if (strcmp(cmd,"login")==0) done_content = FALSE;
                        if (strcmp(cmd,"logout")==0) done_content = FALSE;
			if (done_content)  printf("Content-type: %s\n\n",content_type());
		}
                chan = nntp_open(ini_get(I_NEWSHOST));
                if (chan<0) { goto failed;}
                nntp_setblock(chan,TRUE); /* Set to blocking IO */

                ncpy(cmd,form_find("cmd"),200);
                get_utag(form_find("utag"));
                imsg("Post cmd (%s)\n",cmd);
                if (strcmp(cmd,"post")==0) r_post();
                        else if (strcmp(cmd,"login")==0)  r_login(FALSE);
                        else if (strcmp(cmd,"logout")==0)  r_logout();
                        else if (strcmp(cmd,"config")==0)  r_config();
        }
	else
	{
		int i;
		static int dolatest;
		ncpy(ltemplate,"latest.tpl",BFSZ-10);
		for(i=0;i<argc;i++) {
		   strlwr(argv[i]);
		   if (strncmp(argv[i],"-latest",7)==0) {
		       if (++i<argc) if (strstr(argv[i],"..")==NULL) ncpy(ltemplate,argv[i],BFSZ-10);
		       dolatest = TRUE;break;
		   }
		}
		if (dolatest) {
		    /* use the script path they specify when running from the command prompt */
		    if (strlen(ini_get(I_LATEST_PATH))>0) {
			ncpy(path_script,ini_get(I_LATEST_PATH),BFSZ-10);
		    }
		};
                
		isquery = TRUE;
imsg("Processing command (%.80s)\n",query_find("cmd"));
                get_utag(query_find("utag"));
                ncpy(cmd,query_find("cmd"),200);
                if ((strcmp(cmd,"raw")!=0) && (strcmp(cmd,"article")!=0)&& (strcmp(cmd,"parts")!=0) && !ispressed("cmd_next") && !ispressed("cmd_thread_next") && !ispressed("cmd_thread_last") && !ispressed("cmd_last") && !dolatest) {
                        if (docache) printf("Pragma: cache\n");
                        done_content = TRUE;
                        if (strcmp(cmd,"logout")==0) done_content = FALSE;
			if (ispressed("cmd_logout")) done_content = FALSE;
                        if (done_content) printf("Content-type: %s\n\n",content_type());
                }
                chan = nntp_open(ini_get(I_NEWSHOST));
                if (chan<0) { goto failed;}
                nntp_setblock(chan,TRUE); /* Set to blocking IO */

		if ((strcmp(cmd,"latest")==0)||(dolatest)) {
		    if (strlen(query_find("ltemplate"))!=0) 
			if (strstr(query_find("ltemplate"),"..")==NULL)
			    ncpy(ltemplate,query_find("ltemplate"),BFSZ-10);		    
		    tpl_show(ltemplate);
		    return 0;
		}
                else if (strcmp(cmd,"showini")==0) display_info(argv[0]);
		else if (strcmp(cmd,"raw")==0) r_raw();
		else if (strcmp(cmd,"xover")==0) r_xover();
                else if (strcmp(cmd,"list")==0) r_list();
                else if (strcmp(cmd,"xdebug")==0) r_xdebug();
                else if (strcmp(cmd,"listall")==0) r_listall();
                else if (strcmp(cmd,"article")==0) r_article();
                else if (strcmp(cmd,"parts")==0) r_parts();
                else if (strcmp(cmd,"post")==0) f_post();
                else if (strcmp(cmd,"search")==0) f_search();
                else if (strcmp(cmd,"f_search")==0) f_search();
                else if (strcmp(cmd,"r_search")==0) r_search();
                else if (strcmp(cmd,"r_subscribe")==0) r_subscribe();
                else if (strcmp(cmd,"r_find")==0) r_find();
                else if (strcmp(cmd,"xsearch")==0) r_find();
                else if (strcmp(cmd,"f_find")==0) f_find();
                else if (strcmp(cmd,"follow")==0) f_follow(TRUE);
                else if (strcmp(cmd,"login")==0) f_login();
                else if (strcmp(cmd,"r_login")==0) r_login(FALSE);
                else if (strcmp(cmd,"logout")==0) r_logout();
                else if (strcmp(cmd,"user")==0) r_user();
                else if (strcmp(cmd,"f_config")==0) f_config();
                else if (ispressed("cmd_config")) f_config();
                else if (ispressed("cmd_user")) r_user();
                else if (ispressed("cmd_read")) r_xover();
                else if (ispressed("cmd_grpsearch")) r_grpsearch();
                else if (ispressed("cmd_logout")) r_logout();
                else if (ispressed("cmd_unsub")) r_unsub();
                else if (ispressed("cmd_latest")) cmd_latest();
                else if (ispressed("cmd_related")) cmd_related();
                else if (ispressed("cmd_up")) cmd_up();
                else if (ispressed("cmd_down")) cmd_down();
                else if (ispressed("cmd_search_up")) cmd_search_up();
                else if (ispressed("cmd_search_down")) cmd_search_down();
                else if (ispressed("cmd_tomail_add_thread")) cmd_tomail_add_thread();
                else if (ispressed("cmd_tomail_add")) cmd_tomail_add();
                else if (ispressed("cmd_tomail_del")) cmd_tomail_del();
                else if (ispressed("cmd_post")) f_post();
                else if (ispressed("cmd_find")) f_find();
                else if (ispressed("cmd_follow")) f_follow(TRUE);
                else if (ispressed("cmd_login")) f_login();
                else if (ispressed("cmd_next")) cmd_next();
                else if (ispressed("cmd_last")) cmd_last();
		else if (ispressed("cmd_thread_next")) cmd_thread_next();
		else if (ispressed("cmd_thread_last")) cmd_thread_last();
                else if (ispressed("cmd_catchup")) r_catchup();
                else if (ispressed("xdebug")) r_xdebug();
                else r_list();
        }
        if (strlen(etext)>0) {
                show_error();
        }
        imsg("Program finished ok, etextlen = %d\n",strlen(etext));
        return 0;
failed:
        if ((strcmp(cmd,"article")!=0) && !ispressed("cmd_next") && !ispressed("cmd_last")) {
                if (docache) printf("Pragma: cache\n");
                done_content = TRUE;
                printf("Content-type: %s\n\n",content_type());
        }
        printf("Could not open connection to your news server (%s). \n",ini_get(I_NEWSHOST));
        printf("It may be down at the moment, in which case you could try\n");
        printf("again later.  Also check you have given the correct name in dnewsweb.ini\n");
        return 0;
}
char *decode_basic(char *rest)
{
	char *s;
	int n;
	char uinfo[BFSZ];
	static char user[BFSZ],pass[BFSZ];
	s = strstr(rest,"Basic");
	if (s==NULL) return "";
	if (strlen(s)>200) return "";
	if (strlen(s)<8) return "";
	n = decode_base64(s+6,uinfo);
	if (n<0) return "";
	if (n>BFSZ-1) return "";
	uinfo[n] = 0;
	strcpy(pass,"");
	s = strchr(uinfo,':');
	if (s!=NULL) *s = 0;
	ncpy(user,uinfo,200);
	if (s!=NULL) ncpy(pass,s+1,200);
	return pass;
}
void set_utag(char *user, char *dom)
{
        char bf[BFSZ];
	sprintf(bf,"%s %s",user,dom);
	if (ini_true(I_IGNORE_ADDRESS)) {
		srand(time(NULL));
		sprintf(ukey,"%d",abs(rand()%10000000));
		sprintf(bf,"%s %s:%s",user,dom,ukey);
	}
        get_utag(bf);
}
void show_error(void)
{
        char bf[BFSZ];
        static int done;
        char fname[BFSZ];
        ncpy(bf,etext,200);

        strcpy(fname,"error.tpl");
        if (strstr(etext,"423")!=NULL) strcpy(fname,"missing.tpl");
        if ((!lib_exists(file_tpl(fname))) || done) {
                do_content();
                printf("%s<br>Not found (%s)",etext,file_tpl(fname));
                return;
        }
        done=TRUE;
        do_content();

        var_set("error",etext);
        tpl_show(fname);        
}
int ini_true(int x)
{
        char bf[BFSZ];
        strcpy(bf,ini_get(x));
        strlwr(bf);
        if (strstr(bf,"true")!=NULL) return TRUE;
        return FALSE;
}
static char utag_user[BFSZ];
void get_utag(char *ut)
{
        char *s;
	char bf[BFSZ];

	if (ini_true(I_LOGIN_COOKIE)) {
		if (strlen(ut)==0) {
			ncpy(bf,get_cookie("dnews_utoken"),200);
			plustospace(bf); 
			ut = bf;
		}
	}
	ncpy(utag,ut,200);
        ncpy(guser,ut,200);
	s = strchr(guser,':');
	if (s!=NULL) {
		*s = 0;
		ncpy(ukey,s+1,BFSZ-1);
	}
	ncpy(utag_user,guser,BFSZ-1);
        s = strchr(guser,' '); 
        if (s!=NULL) {
                *s = 0;
                ncpy(udom,s+1,BFSZ-1);
        }

        
        if (strlen(ini_get(I_POST_DOMAIN))>0) strcpy(udom,ini_get(I_POST_DOMAIN));
        if (strcmp(udom,"")==0) strcpy(udom,ini_get(I_NEWSHOST));
        ncpy(utage,utag,BFSZ-1);
        lib_encode(utage);
        imsg("utag got = (%.80s) \n",utag);

}
int ispressed(char *s)
{
        char bf[BFSZ];
        if (strlen(query_find(s))>0) {
                imsg("=========PRESSED BUTTON (%s)\n",s);       
                return TRUE;
        }
        sprintf(bf,"%s.x",s);
        if (strlen(query_find(bf))>0) {
                imsg("=========PRESSED BUTTON.x (%s)\n",bf);    
                return TRUE;
        }

        return FALSE;
}
/*
        sprintf(bf,"group rec.humor\015\012"); nntp_write_s(c,bf,strlen(bf)); 
        sprintf(bf,"article\015\012"); nntp_write_s(c,bf,strlen(bf)); 
        sprintf(bf,"quit\015\012"); nntp_write_s(c,bf,strlen(bf)); 
        n = nntp_read(c,out,1000);
        for (;n>=0;) {
                out[n] = 0;
                printf("%s",out);
                n = nntp_read(c,out,1000);
              
        }
        return 0;
*/
int nntp_read_timeout(int c, char *bf, int sz)
{
        int i;
        int r;
        r = nntp_chanwait(c,60);
        if (r) return nntp_read(c,bf,sz);       
        do_content();
        emsg("Channel timedout while trying to read from news server, try later\n");
	exit(0);
        return -1;      
}

static String *instr;
int read_lines(void)
{
        int n;
        char bf[3000];
        char *s;
wantmore:
        n = nntp_read_timeout(chan,bf,2000);
        if (n<0) return FALSE;
        bf[n] = 0;
        str_addsn(instr,bf);

        s = str_s(instr) + str_len(instr) - 1;
        dmsg("Last char {%d}\n",*s);
        if (*s != '\012') goto wantmore;
        return TRUE;
}
static char nntp_status[BFSZ];
int group_match(char *a, char *b);
int group_allow(char *group)
{
        char bf[BFSZ];
        char g[BFSZ];
        ncpy(g,group,BFSZ-1);
        ncpy(bf,ini_get(I_ALLOW),BFSZ-1);
        if (!group_match(bf,g)) {
                printf("Sorry, you are not permitted access to (%s) %d",group,strlen(group));
                printf("via this DNEWSWEB gateway (%s) %d\n",bf,strlen(bf));
                return FALSE;
        }
        return TRUE;
}
int group_allow_silent(char *group)
{
        char bf[BFSZ];
        char g[BFSZ];
        ncpy(g,group,BFSZ-1);
        ncpy(bf,ini_get(I_ALLOW),BFSZ-1);
        if (!group_match(bf,g)) {
                return FALSE;
        }
        return TRUE;
}

int read_pop(int chan)
{
        int n;
        char bf[3000];
        char *s;
        strcpy(nntp_status,"(no data)");
        n = nntp_read_timeout(chan,bf,200);
        if (n<0) return FALSE;
        bf[n] = 0;
        s = strchr(bf,'\n'); if (s!=NULL) *s = 0;
        s = strchr(bf,'\r'); if (s!=NULL) *s = 0;
        imsg("read_pop (%s) \n",bf);
        ncpy(nntp_status,bf,BFSZ-1);
        if (nntp_status[0]=='+') return TRUE;
        return FALSE;
}
int read_status(void)
{
        char *s,*s2;
        int slen;
        if (instr==NULL) instr = str_new();
        get_line_clear();
        str_copysn(instr,"");   
        read_lines();
        s = str_s(instr);
        s2 = strchr(s,'\012');
        if (s2==NULL) return FALSE;
        *s2 = 0;
        ncpy(nntp_status,s,BFSZ-1);
        slen = s2-s+1;
        if (str_len(instr)>(slen)) {
                memmove(s,s2+1,str_len(instr)-slen+1);
                str_setlen(instr,str_len(instr)-slen);
        } else  str_copysn(instr,"");   
        if (nntp_status[0]=='2') return TRUE;
        if (nntp_status[0]=='3') return TRUE;
        return FALSE;
}
char *get_linex(String *instr)
{
        static char bf[BFSZ];
        char *s;
        char *s2;
        int slen;
        s = str_s(instr);
        if (s==NULL) return NULL;
        s2 = strchr(s,'\012');
        if (s2==NULL) return NULL;
        *s2 = 0;
        ncpy(bf,s,BFSZ-1);
        slen = s2-s+1;
        if (str_len(instr)>(slen)) {
                memmove(s,s2+1,str_len(instr)-slen+1);
                str_setlen(instr,str_len(instr)-slen);
        } else  str_copysn(instr,"");   

        return bf;
}
static int gupto;
void get_line_clear(void)
{
        gupto = 0;
        if (instr==NULL) return;
        str_copysn(instr,"");
}
static int nowrap;
char *get_line(String *instr);
char *get_line_nowrap(String *instr)
{
        char *s;
        nowrap = TRUE;
        s = get_line(instr);
        nowrap = FALSE;
        return s;
}
static int unwraphead = FALSE;
char *get_line_head(String *instr)
{
        char *s;
        unwraphead = TRUE;
        s = get_line(instr);
        unwraphead = FALSE;
        return s;
}

char *get_line(String *instr)
{
        static char bf[BFSZ];
        char *s;
        int noskip = FALSE;
        char was;
        char *s2;
        int slen;
        if (instr==NULL) return NULL;
        s = str_s(instr);
        if (s==NULL) goto fail;
        s+=gupto;
        if (*s=='\r') {s++; gupto++;}
        if (*s=='\n') {s++; gupto++;}
again:
        for (s2=s;*s2!=0;s2++) if ((*s2=='\n') || (*s2=='\r')) break;
        if (*s2==0) goto fail;
	if (unwraphead) {
		if ((*s!='\n') && (*s!='\r')) 
		  if ( (s2[2]==' ') || (s2[2]=='\t') ) {
			s2[0] = ' ';
			s2[1] = ' ';
			goto again;
		}
	}

        if (((s2-s)>500) && (!nowrap)) {
                /* Long line, wrap it on the last space if possible*/
                s2 = strchr(s+500,' ');
                if (s2==NULL) {s2 = s+500; noskip = TRUE;}
                if (s2>(s+599)) {s2 = s+500; noskip = TRUE;}
                was = *s2;
                *s2 = 0;
                ncpy(bf,s,BFSZ-1);
                *s2 = was;
                gupto += s2-s+1;
                if (noskip) gupto--;
        } else {
                *s2 = 0;
                ncpy(bf,s,BFSZ-1);
                gupto += s2-s+1;
        }
        /*strcat(bf,"\r");*/
        if (gupto==str_len(instr)) str_copysn(instr,"");
        return bf;
fail:
        str_copysn(instr,"");
        return NULL;
}
int read_xover(void)
{
        char *s;
        dmsg("inside read_xover\n");
        if (instr==NULL) instr = str_new();
        for (;TRUE;) {
                dmsg("inside read_xover\n");
                if (str_len(instr)==3) if (strcmp(str_s(instr),".\015\012")==0) break;
                if (str_len(instr)>=5) {
                        s = str_s(instr) + str_len(instr) - 5;
                        if (strcmp(s,"\015\012.\015\012")==0) break;
                        if (strcmp(s,"\015\012.\015\012")==0) break;
                }

                read_lines();
        }
        if (str_len(instr)>2) str_setlen(instr,str_len(instr)-3);
        return (str_len(instr)==0);
}
void show_xline(char *s);
void show_xbar(void)
{
        printf("<table border>"); 
        printf("<tr>");
        if (gfrom>group_from) { 
                printf("<td><a href=\"%s?cmd=xover&group=%s&from=%d\">Previous Page</a>",path_script,towww(group),gfrom-gmax);
        }
        if (gto<group_to) { 
                printf("<td><a href=\"%s?cmd=xover&group=%s&from=%d\">Next Page</a>",path_script,towww(group),gto);
                printf("<td><a href=\"%s?cmd=xover&group=%s\">Recent Items</a>",path_script,towww(group));
        } 
        printf("<td><a href=\"%s?cmd=list\">Standard Groups</a>",path_script);
        printf("<td><a href=\"%s?cmd=listall\">All Groups</a>",path_script);
        printf("<td><a href=\"%s?cmd=post&group=%s\">Post</a>",path_script,towww(group));
        printf("<td><a href=\"%s?cmd=f_find&group=%s\">Search Group</a>",path_script,towww(group));
        printf("</table> \n");
}
void tpl_init_sbar(int from, int to, int total, char *key)
{
        char bf[BFSZ];
        if (from>1) { 
                sprintf(bf,"%s?cmd=r_search&key=%s&from=%d&to=%d&utag=%s",path_script,lib_encode(key),from-page_size(),from,utage);
                var_set("b_prev",bf);
                var_set("to_up",int_str(from));
                var_set("from_up",int_str(from-page_size()));
        }
        if (to<total) { 
                sprintf(bf,"%s?cmd=r_search&key=%s&from=%d&to=%d&utag=%s",path_script,lib_encode(key),to,to+page_size(),utage);
                var_set("b_next",bf);
                var_set("to_down",int_str(to+page_size()));
                var_set("from_down",int_str(to));

        } 
        sprintf(bf,"%d",from);
        var_set("from",bf);
        sprintf(bf,"%d",to);
        var_set("to",bf);
}
void show_sbar(int from, int to, int total, char *key)
{
        printf("<table border>"); 
        printf("<tr>");
        if (from>1) { 
                printf("<td><a href=\"%s?cmd=r_search&key=%s&from=%d&to=%d\">Previous Page %d-%d</a>",path_script,lib_encode(key),from-page_size(),from,from-page_size(),from);
        }
        if (to<total) { 
                printf("<td><a href=\"%s?cmd=r_search&key=%s&from=%d&to=%d\">Next Page %d-%d</a>",path_script,lib_encode(key),to,to+page_size(),to,to+page_size());
        } 
        printf("<td><a href=\"%s?cmd=list\">Standard Groups</a>",path_script);
        printf("<td><a href=\"%s?cmd=listall\">All Groups</a>",path_script);
        printf("<td><a href=\"%s?cmd=f_find&group=%s\">Search Group</a>",path_script,towww(group));
        printf("</table> \n");
}
void show_xover(void)
{ 
        char *s;


        s = get_line_nowrap(instr);
        for (;s!=NULL;) {
                dmsg("Show sxline %s\n",s);
                show_xline(s);
                s = get_line_nowrap(instr);
        }
}
void show_search(void)
{ 
        char *s;

        s = get_line_nowrap(instr);
        for (;s!=NULL;) {
                show_xline(s); /* decode xover information */
                s = get_line_nowrap(instr);
        }
        show_xsearch();
}


void show_xsearch(void)
{
        int i;
        char bf[BFSZ];
        char *s;
        printf("<ul>\n");
        for (i=0; i<nitem; i++) {
                ncpy(bf,x_group[i],BFSZ-1);
                s = strchr(bf,':'); if (s!=NULL) {*s=0; s++;} else s = bf;
                printf("<li>Score %s, <a href=\"%s?cmd=article&group=%s&item=%s&utag=%s\">",x_score[i],path_script,towww(bf),s,utage);
                printf("%s</a> - %s (%s) <br>\n",value_encode(x_subject[i]), email_name(x_from[i]),x_lines[i]);
        }
        printf("</ul>\n");

}


void show_dlist(void)
{ 
        char *s;


        s = get_line_nowrap(instr);
        for (;s!=NULL;) {
                show_dline(s);
                s = get_line_nowrap(instr);
        }
}
void netwin_advert(void)
{
        printf("<hr> <FONT SIZE=-2>\n");
        printf("<a href=\"http://netwinsite.com/\"> ");
        printf("DNEWSWEB %s Copyright &copy; <I>NetWin Ltd</I>\n",DNEWS_VERSION);
        printf("</a> \n");
        printf("</FONT> \n");
}
int head_get(char *field, char *val, char *line)
{
        char bf[BFSZ];
        char bf2[BFSZ];
        ncpy(bf,line,BFSZ-1);
        strlwr(bf);
        if (strncmp(bf,field,strlen(field))==0) {
                ncpy(bf2,line+strlen(field)+1,BFSZ-80);
                ncpy(val,head_decode(bf2),BFSZ-80);
        }
        return TRUE;
}
#define MAXIMG 500000
void show_article_part(int wanted);

void show_article_part(int wanted)
{ 
	int uucount;
	char *s;
        char *s2;
        int gothead;       
        int n;
        char subject[BFSZ];
        int isuu = FALSE;
        char from[BFSZ];
        char tmp[BFSZ];
        char date[BFSZ];
        char boundary[BFSZ];
        char content[BFSZ];
        char newsgroups[BFSZ];
        char *out;
        int nout;
        int findimage = FALSE;
        int item = atoi(query_find("item"));
        int related = item;
        int got=0;
	int r;
        int ismsg=FALSE;
	int isvcard = FALSE;
	if (b_item>=0) item = b_item;
	if (wanted==200) {findimage = TRUE; gothead = TRUE;}
        if (wanted==99) wanted = 0;

	if (str_len(instr)>MAXIMG) out = mymalloc(str_len(instr));
        else out = mymalloc(MAXIMG);
        strcpy(boundary,"none");
        strcpy(subject,"");
        strcpy(from,"");
        strcpy(content,"");
        strcpy(date,"");
        strcpy(newsgroups,"");
        related = item ;
        if (related<1) related = 1;
#ifdef FIX_STDOUT
        _setmode(_fileno(stdout),_O_BINARY);
#endif
/*       printf("Content-type: text/html\n\n"); */
/*  fopen
        printf("MIME-Version: 1.0\n"); */

/*      printf("Content-Type: image/x-xbitmap\n");
        printf("\n");
        printf("#define back_width 20\n");
        printf("#define back_height 23\n");
        printf("static char back_bits[] = {\n");
        printf(" 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0f,0x00,0x80,0x0f, \n");
        printf(" 0x00,0x80,0x0f,0x00,0x80,0x0f,0x00,0x80,0x0f,0x00,0x80,0x0f,0x60,0x80,0x0f, \n");
        printf(" 0x70,0x80,0x0f,0x78,0x00,0x00,0xfc,0xff,0x0f,0xfe,0xff,0x07,0xff,0xff,0x03, \n");
        printf(" 0xfe,0xff,0x01,0xfc,0xff,0x00,0x78,0x00,0x00,0x70,0x00,0x00,0x60,0x00,0x00, \n");
        printf(" 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; \n");
return;
        printf("Content-type: image/jpeg; name=\"test.jpg\"\n");
        f = fopen("test.jpg","rb");
        if (f==NULL) {perror("test.jpg"); return;}
        n = fread(bf,1,100000,f);

        printf("Content-length: %d\n",n); 
        printf("\n");
        fwrite(bf,1,n,stdout);
        return;
*/


	uucount=0;
	if (!gothead) s = get_line_head(instr);                    
        else s = get_line(instr);                    
        for (;s!=NULL;) {
		s2 = strchr(s,'\015') ;
                if (s2!=NULL) *s2 = 0;
                s2 = strchr(s,'\012') ;
                if (s2!=NULL) *s2 = 0;
                if (strlen(s)==0) break;
                if (wanted==0) head_get("content-type:",content,s);
                s2 = strstr(s,"boundary=");
                if (s2==NULL) s2 = strstr(s,"Boundary=");
                if (s2!=NULL) {
			s2 = strchr(s2,'"');
                        strcpy(boundary,"--");
                        if (s2!=NULL) ncpy(boundary+2,s2+1,BFSZ-10);
                        s2 = strchr(boundary,'"');
                        if (s2!=NULL) *s2 = 0;
	                head_get("content-type:",content,s);
                }
                /* head_get("subject:",subject,s); */
	        if (!gothead) s = get_line_head(instr);
                else s = get_line(instr);
        }
        nout = 0;
        if (findimage) if (strlen(content)>0) wanted = 0;
/*
Content-Type: image/jpeg;
        name="BusScene.jpg"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
        filename="BusScene.jpg"	
*/

	if (wanted==0) {
                imsg("Content-type: %s\n",content);
		if (strlen(content)==0) strcpy(content,"image/jpeg; name=\"test.jpg\"");
                printf("Content-type: %s\n",content);
                gothead = TRUE;
        }
        for (;s!=NULL;) {
                s2 = strchr(s,'\015') ;
                if (s2!=NULL) *s2 = 0;
                s2 = strchr(s,'\012') ;
                if (s2!=NULL) *s2 = 0;
                
                if (!isuu) {
		    if (strncmp(s,"begin",5)==0) uucount++;
		    /* brian - checks uucount!= 0 to ensure there is uuencoding used */
		    /* also if wanted (mime part) == 100 then there is no mime so
		       ignore the check to ensure we are in the right mime part */
		    /* brian - why is got set to wanted + 1 below ?????? */
		    if (((wanted==100)||(got==wanted)||(got==wanted+1))
			&&(uucount!=0)&&(uucount==atoi(query_find("uucount"))))
		    { 
                        isuu = TRUE;
                        strlwr(s);
                        done_content = TRUE;
                        if (strstr(s,".gif")!=NULL)  printf("Content-type: image/GIF\n");
                        else if (strstr(s,".zip")!=NULL)  printf("Content-type: application/x-zip-compressed\n");
                        else if (strstr(s,".exe")!=NULL)  printf("Content-type: application/octet-stream\n");
                        else if (strstr(s,".doc")!=NULL)  printf("Content-type: application/octet-stream\n");
                        else if (strstr(s,".xls")!=NULL)  printf("Content-type: application/octet-stream\n");
                        else if (strstr(s,".com")!=NULL)  printf("Content-type: application/octet-stream\n");
                        else if (strstr(s,".txt")!=NULL)  printf("Content-type: text/plain\n");
                        else if (strstr(s,".ini")!=NULL)  printf("Content-type: text/plain\n");
                        else if (strstr(s,".jpg")!=NULL)  printf("Content-type: image/JPEG\n");
                        /*else if (strstr(s,".avi")!=NULL)  printf("Content-type: audio/avi\n");
                        else if (strstr(s,".mpg")!=NULL)  printf("Content-type: video/mpeg\n");
                        else if (strstr(s,".mpeg")!=NULL)  printf("Content-type: video/mpeg\n");
                        */
                        else if (strstr(s,".htm")!=NULL)  printf("Content-type: text/html\n");
                        else if (strstr(s,".html")!=NULL)  printf("Content-type: text/html\n");
                        else if (strstr(s,".jpeg")!=NULL)  printf("Content-type: image/JPEG\n");
                        else {
                            printf("Content-type: application/octet-stream\n");    
			    /* printf("Content-type: image/JPEG\n");*/
                        }
                        
                    }
                } else { 
                  if (isuu) {
                        if (strncmp(s,"end",3)==0) break;
                        if (strcmp(s,"`")==0) break;
                        if (s[0]!=0) {
			        /*imsg("************* decode_uu(s='%s',out'%d'+nout'%d'='%d' '%s') about to die?\n",s,out,nout,out+nout,out+nout); */
                                n = decode_uu(s,out+nout);
                                nout += n;
                        }
                  }
                }
                
                if (!isuu) {
                if (!gothead) {
                        boundary_add(s);
                        if (strstr(s,"message/rfc822")!=NULL) ismsg = TRUE;
                        if (strlen(s)==0) {
                                if (!ismsg) gothead = TRUE;
                                ismsg = FALSE;
                        }
                }
                if (findimage) if (!gothead) {
                        ncpy(tmp,s,BFSZ-1);
                        strlwr(tmp);
                        if ( (strstr(tmp,"jpeg")!=NULL) ||
                                (strstr(tmp,"jpg")!=NULL) ||
                                (strstr(tmp,"image")!=NULL) ||
                                (strstr(tmp,"gif")!=NULL) )
                        {
                                wanted = got;
                                goto showit;
                        }
                        if (strlen(s)==0) gothead = TRUE;
                }
		if ((strstr(s,boundary)!=NULL) || (boundary_check(s))) {
		    gothead = FALSE; got++;
		    uucount = 0; 
                } else if (got==wanted) {
		 
showit:         
		if (strlen(s)==0) gothead = TRUE;
                else {
                        if (!gothead) {
/*                              {char *zz;
                                        zz = strchr(s,';');
                                        if (zz!=NULL) *zz = 0;
                                }
*/
                                imsg("Attach Head(%s)\n",s);

                                ncpy(tmp,s,BFSZ-1);
                                strlwr(tmp);
                                if (strstr(tmp,"message/rfc822")!=NULL) ismsg = TRUE;
                                if (strstr(tmp,"text/x-vcard")!=NULL) isvcard = TRUE;
                                if (strstr(tmp,"x-uue")!=NULL) got = wanted+1;
                                printf("%s\n",s);
                        } else {
			  if (isvcard) {
				  strcat(out+nout,s);
				  nout += strlen(s);
				  strcat(out+nout,"\n");
				  nout += 1;
			  } else {
	                          n = decode_base64(s,out+nout);
	                          if (n<0) emsg("Base 64 encoding is corrupt {%s} \n",s);
	                          nout += n;
			  }
                        }
                 }
                } 
                if (nout<0) break; 
                }
                if (!gothead) s = get_line_head(instr);
		else s = get_line(instr);
        }
        printf("Content-length: %d\n",nout); 
	printf("\n");
	r = fwrite(out,1,nout,stdout);
/*	imsg("Wrote %d/%d bytes with fwrite %s\n",r,nout,strerror(errno));*/
	if (fflush(stdout)!=0) {
		imsg("Flush failed %s\n",strerror(errno));
	}
	return;
}
void do_content(void)
{
        if (done_content) return;
        printf("Content-type: %s\n\n",content_type());
        done_content = TRUE;
}
int lib_msec(void)
{
        return 1;
}
static char msgid[BFSZ];
static  char subject[BFSZ];
static  char from[BFSZ];
static  char h_ref[BFSZ];
static char contenttype[BFSZ];
static char mimeversion[BFSZ];
static char mimeboundary[BFSZ];
void show_article1(void)
{ 
        char *boundary;
        char *boundary2;
        char *s;
        char date[BFSZ];
        char bf[4000];
        char newsgroups[BFSZ];
        strcpy(subject,"");
        strcpy(from,"");
        strcpy(date,"");
        strcpy(msgid,"");
        strcpy(newsgroups,"");
        strcpy(contenttype,"");
        strcpy(mimeversion,"");
        strcpy(mimeboundary,"");

        s = get_line(instr);
        for (;s!=NULL;) {
                if (strcmp(s,"")==0) break; /*bazil*/
                head_get("content-type:",contenttype,s);
                head_get("mime-version:",mimeversion,s);
                /* check for mime boundary and remember it
                   so we can remove it when quoting the message */
                boundary = strstr(s,"boundary=\"");
                if (boundary!=NULL) {
                    boundary+=10;
                    boundary2=strchr(boundary,'\"');
                    if (boundary2!=NULL) {
                        if ((boundary2-boundary)<500) ncpy(mimeboundary,boundary,boundary2-boundary);
                        else ncpy(mimeboundary,boundary,500);
                    };
                };
                head_get("subject:",subject,s);
                head_get("date:",date,s);
                head_get("from:",from,s);
                head_get("references:",h_ref,s);
                head_get("message-id:",msgid,s);
                head_get("newsgroups:",newsgroups,s);
                s = get_line(instr);
        }
	if (strlen(subject)==0) strcpy(subject,"(No subject)");
        var_set("h_subject",value_encode(subject));
        var_set("h_date",date);
	var_set("h_date_numeric",h_date_numeric(date)); /*brian123*/
        var_set("h_message-id",value_encode(msgid));
        var_set("h_from",value_encode(from));
        sprintf(bf,"%s %s",h_ref,msgid);
        var_set("h_references",eoltospace(value_encode(bf)));
        var_set("h_message-id",msgid);
        var_set("h_newsgroups",newsgroups);
}
void show_article3(void)
{ 
        char *s;
        s = strchr(from,'\015'); 
        if (s!=NULL) *s = 0;
        printf("%s wrote:",from);
        s = get_line(instr);
        for (;s!=NULL;) {
                printf(">%s",s);
                s = get_line(instr);
        }
}
void f_post(void)
{
        f_follow(FALSE);
}
void f_postXX(void)
{
        ncpy(group,query_find("group"),BFSZ-1);
        printf("<html><head><title> Post new item to group %s  </title>",group); 
        printf("</head><body>"); 
        printf("<form method=post action=\"%s\"> \n",path_script);
        printf(" <input type=hidden name=\"cmd\" value=\"post\"> \n");
        printf(" <input type=hidden name=\"group\" value=\"%s\"> \n",group);
        printf("Newsgroup: %s<br>\n",group);
        printf("From: <input name=\"from\" size=20 > (Give EMail address)<br>\n");
        printf("Subject <input name=\"subject\" size=50 > (Required)<br>\n");
        printf("Please enter your message text here: (press enter at the end of each line)<br>\n");
        printf("<textarea name=\"message\" cols=65 rows=8>  </textarea> <br>\n");
        printf("<input type=submit name=\"action\" value=\"Post Message\" >\n");
        printf("</form>\n");
        netwin_advert();
        printf("</body>"); 
        printf("</html>"); 
}
void f_config(void)
{
        char bf[BFSZ];
        tpl_init();

        if (!islogin()) {
                zmsg("Sorry, you are not logged in\n");
                return;
        }

        user_read(utag);
        var_set("conf_name",user_get("name"));
        var_set("conf_reply",user_get("reply"));
        ncpy(bf,user_get("sort"),200); strlwr(bf);
        if (strcmp(bf,"subject")==0) var_set("conf_sort_subject","selected");
        if (strcmp(bf,"thread")==0) var_set("conf_sort_thread","selected");
        if (strcmp(bf,"date")==0) var_set("conf_sort_date","selected");
        var_set("conf_sort",user_get("sort"));
        var_set("conf_sig",cr_decode(user_get("sig")));
        tpl_show("config.tpl");
}

void r_config(void)
{
        user_read(utag);
        if (!islogin()) {
                zmsg("Sorry, you are not logged in\n");
                return;
        }
        user_set("name",form_find("conf_name"));
        user_set("reply",form_find("conf_reply"));
        user_set("sort",form_find("conf_sort"));
        user_set("sig",cr_encode(form_find("conf_sig")));
        
        user_write(utag);
        r_user();
}

void r_login(int nooutput)
{
        char user[BFSZ],pass[BFSZ],pop[BFSZ];
        char etxt[BFSZ];
        char bf[BFSZ];
	char ue[BFSZ];
        char *s;
        int id = atoi(form_find("loginid"));
        imsg("r_login(%s)\n",thisuser);
       
	if (!open_status()) return ;

        ncpy(user,either_find("user"),BFSZ-1);
        ncpy(pass,either_find("pass"),BFSZ-1);
        ncpy(pop,either_find("pop"),BFSZ-1);
        if (strlen(pass)==0) if (strlen(thisuser)>0) {
                imsg("web login (%s) \n",thisuser);
                ncpy(user,thisuser,200);
                goto isok;
        }
        if (!pop_check(user,pass,pop,etxt)) {
                var_set("login_error",etxt);
                set_id();
                tpl_show("login.tpl");
                return;         
        }
isok:
        set_utag(user,pop);
	ncpy(ue,utag,100);
	lib_encode(ue);
	printf("Set-Cookie: dnews_utoken=%s; expires=%s\n",ue,cookie_date_plus(60*60*12));
	imsg("Set-Cookie: dnews_utoken=%s; expires=%s\n",ue,cookie_date_plus(60*60*12));
        done_content = TRUE;
	printf("Content-type: %s\n\n",content_type());
        user_read(utag);

        imsg("login id's (%s) (%d)\n",user_get("loginid"),id);
        if (!ini_true(I_WEB_LOGIN)) if (!ini_true(I_IGNORE_ID)) if (atoi(user_get("loginid"))==id) {
                if (!islogin()) {
                 sprintf(bf,"Sorry, login form already used");
                 var_set("login_error",bf);
                 set_id();
                 tpl_show("login.tpl");
                 return;
                }
        }
        /* Record that user is logged in, and store */
	if (ini_true(I_USER_CLEAR)) {
		imsg("Clearing existing user info\n");
		xuser_clear();
	}
        srand( (unsigned)time( NULL ) );
        sprintf(bf,"%d",rand());
        user_set("cookie",bf);
        sprintf(bf,"%d",id);
        user_set("loginid",bf);
        user_set("ukey",ukey);
        user_set("remote_addr",mygetenv("REMOTE_ADDR"));
        sprintf(bf,"%d",lib_gmtime());
        user_set("login_time",bf);

	if (ini_true(I_AUTH_NNTP)) {
		user_set("nntp_pass",pass);
	}
        imsg("user write\n");

        
	
	if (ngroups==0) {
                s = strtok(ini_get(I_AUTO_SUBSCRIBE),", ");
                for (;s!=NULL;) {
                        group_add(s);
                        s = strtok(NULL," ,");
                }
        }
        user_write(utag);
        imsg("r_user()\n");
        if (!nooutput) {
		if (strlen(form_find("group"))>0) {
			cmd_latest();
		} else {
			r_user();
		}
	}
}

void r_unsub(void)
{
        user_read(utag);
        group_del(query_find("unsub"));
        user_write(utag);
        r_user();
}
void r_subscribe(void)
{
        user_read(utag);
        group_add(query_find("group"));
        user_write(utag);
        r_user();
}
void r_grpsearch(void)
{
        tpl_init();
        if (!open_status()) {zmsg("News host not responding1: %s",nntp_status); return;}
        if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}

        /* Show user.tpl , fetch list of groups, and items for each group */
        var_set("wild",query_find("wild"));
        if (strlen(query_find("wild"))<3) {zmsg("Please give at least 3 characters to search for"); return;}
        if (ini_true(I_USE_XACTIVE))
	    tcp_printf(chan,"LIST XACTIVE *%s*",query_find("wild"));
	else
	    tcp_printf(chan,"LIST ACTIVE *%s*",query_find("wild"));
        if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        if (read_xover()) var_set("no_match","bazil");
	tpl_show("grpsrch.tpl");
}
int open_status(void)
{
        static int done;
        if (done) return TRUE;
        done = TRUE;
        return read_status();
}
void r_user(void)
{
        tpl_init();
        user_read(utag);
        if (!open_status()) {zmsg("nntp open failed"); return;}
        if (!islogin()) {
                imsg("user not logged, showing top form instead\n");
                r_list();
/*              do_login("Sorry, you are not logged in");*/
                return;
        }


        /* Show user.tpl , fetch list of groups, and items for each group */
        if (!open_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}

        group_fetch();

        tpl_show("user.tpl");
}
typedef struct GINFO {
        char *name;
         int lasttime; int upto; int lastupto; 
         int curupto; int total;
} Ginfo;
#define MAX_SUB 1000
static Ginfo groups[MAX_SUB];
static char tpl_groups[15000];
static char *uinfo[100];
static char *uinfo_val[100];
static int nuinfo;
void group_add(char *s)
{
        int i;
        imsg("Add group, currently %d\n",ngroups);
        for (i=0; i<ngroups; i++) {
                if (strcmp(groups[i].name,s)==0) return;
        }
        groups[ngroups++].name = strdup(s);
}
void group_del(char *s)
{
        int i;
        imsg("Remove group (%s), currnetly %d\n",s,ngroups);
        for (i=0; i<ngroups; i++) {
                if (strcmp(groups[i].name,s)==0) {
                        for (;i<(ngroups-1); i++) {
                                groups[i] = groups[i+1];
                        }
                        ngroups--;                      
                }
        }
        imsg("Could not find that group(%s)\n",s);
}

void tpl_show_gsearch(void)
{
        char bf[BFSZ];
        char *s;
        int xend;
        int i;
        int n,from;
	int np;
	char *p[30];

        s = get_line(instr);
	/*test.new 3 3 y nitems */
        for (;s!=NULL;) {
	        np = token_split(s,p," ",20);
                var_set("name",p[0]);
		if (!group_allow_silent(p[0])) goto nextone;
                var_set("name_ref",towww(p[0]));
		if (ini_true(I_USE_XACTIVE)) {
			if (np>4) var_set("total",p[4]);
		} else {
			if (np<3) goto nextone;
			xend = atoi(p[1]);
			xend -= atoi(p[2]) - 1;
			var_set("total",int_str(xend));
		}
		ncpy(bf,tpl_groups,500);
                s = tpl_replace_vars(bf);
                printf("%s\n",s);
nextone:        s = get_line(instr);
        }
}

void tpl_show_groups(void)
{
        char bf[100000];
        char *s;
        int i;
        int n,from;
        imsg("tpl_show_groups, %d groups\n",ngroups);
        for (i=0; i<ngroups; i++) {
	    imsg("show_groups %d/%d %s\n",i,ngroups,groups[i].name);
	    var_set("name",groups[i].name);
	    var_set("name_ref",towww(groups[i].name));
	    n = groups[i].curupto - groups[i].lastupto;
	    imsg("New items %d, %d - %d\n",n,groups[i].curupto,groups[i].lastupto);
	    if (n>groups[i].total) n = groups[i].total;
	    if (n<0) n = 0;
	    sprintf(bf,"%d",n);
	    var_set("new",bf);
	    if (n==0) {
		    var_set("isnew","false");
	    } else {
		    var_set("isnew","true");
	    }
	    from = groups[i].lastupto;
	    if (from==0) from = groups[i].curupto-20;
	    sprintf(bf,"%d",from);
	    var_set("from",bf);
	    sprintf(bf,"%d",groups[i].total);
	    var_set("total",bf);
	    strcpy(bf,tpl_groups);
	    s = tpl_replace_vars(bf);
	    printf("%s\n",s);
	}
	imsg("show_groups finished\n");
}

void tpl_show_group_list(void)
{
        char bf[BFSZ];
        char *s, *line;
        int i;
        int n,from;

		char *name,*groups;
		int lastupto,curupto,total;
		String *group_instr;
		int group_gupto;

        if (!open_status()) {zmsg("Could not read opening message - %s",nntp_status); return;}
 
		groups=ini_get(I_GROUP_LIST);
		imsg("Showing groups %s\n",groups);
		if (groups[0]=='\0') 
			tcp_printf(chan,"LIST");
		else
			tcp_printf(chan,"LIST ACTIVE %s",groups);
		if (!read_status()) {zmsg("Could not list groups - %s",nntp_status); return;}
		read_xover();
		group_instr=instr;
		instr = str_new();

		while((line=get_line_nowrap(group_instr))!=NULL && (line[0]!='.')) {
			imsg("Processing [%s]\n",line);
			name=strtok(line," \n\t");
			lastupto=atoi(strtok(NULL," \n\t"));
			curupto=atoi(strtok(NULL," \n\t"));

			group_gupto=gupto; /* backup gupto since get_line uses the global variable*/
			tcp_printf(chan,"group %s",name);
			/*imsg("sent group %s\n",name);*/
			if (!read_status()) {zmsg("Could not read group %s - %s",name, nntp_status); return;}
			/*imsg("status=%s\n",nntp_status);*/
			strtok(nntp_status," \n\t");
			total=atoi(strtok(NULL," \n\t"));
			gupto=group_gupto; /* restore gupto*/
			
			/*imsg("Name %s last %d cur %d\n",name,lastupto,curupto);*/

                var_set("name",name);
                var_set("name_ref",towww(name));
                n = curupto - lastupto;
                imsg("New items %d, %d - %d\n",n,curupto,lastupto);
                if (n>total) n = total;
                if (n<0) n = 0;
                sprintf(bf,"%d",n);
                var_set("new",bf);
                if (n==0) {
                        var_set("isnew","false");
                } else {
                        var_set("isnew","true");
                }
                from = lastupto;
                if (from==0) from = curupto-20;
                sprintf(bf,"%d",from);
                var_set("from",bf);
                sprintf(bf,"%d",total);
	        var_set("total",bf);
                ncpy(bf,tpl_groups,4000);
                s = tpl_replace_vars(bf);
                printf("%s\n",s);
        }
}

char *user_file(char *xuser)
{
        char user[BFSZ];
        char hash[BFSZ];
        char *s;
        char work[BFSZ];
        static char bf[BFSZ];
        ncpy(user,xuser,400);
        strlwr(user);
        for (s=user;*s!=0;s++) {
                if (xisspace(*s)) *s = '_';
                if (*s=='.') *s = '_';
                if (!isalnum(*s)) *s = '_';
        }
	if (ini_true(I_USE_HOME)) {
		ncpy(work,mygetenv("HOME"),BFSZ-1);
	        sprintf(bf,"%s/%s.dat",work,user);
	        return bf;
	}

        ncpy(hash,user,2);
        strcpy(work,ini_get(I_WORKAREA));
        if (strlen(work)==0) strcpy(work,ini_get(I_TEMPLATES));
        
        sprintf(bf,"%s/%s/%s.dat",work,hash,user);
        return bf;
}
char *ini_work(char *fname)
{
        char work[BFSZ];
        static char bf[BFSZ];
        strcpy(work,ini_get(I_WORKAREA));
        if (strlen(work)==0) strcpy(work,ini_get(I_TEMPLATES));
        
        sprintf(bf,"%s/%s",work,fname);
        return bf;
}
int xuser_clear(void)
{
	nuinfo = 0;	
}
int user_write(char *xuser)
{
        FILE *f;
        Ginfo *g;
        int i;
	char user[BFSZ];
	char *s;

	ncpy(user,xuser,200);
	s = strchr(user,':'); 
	if (s!=NULL) *s = 0;

        imsg("user_write(%.80s)\n",user);
        f = fopen(user_file(user),"w");
        if (f==NULL) {
                lib_createdir(user_file(user));
                f = fopen(user_file(user),"w");
        }
        if (f==NULL) {
                do_content();
                emsg("Could not create (%s) (%s) \n",user_file(user),strerror(errno));
                return FALSE;
        }
        for (i=0; i<nuinfo; i++) {
		if (i>90) break;
                fprintf(f,"%s %s\n",uinfo[i],uinfo_val[i]);
        }
        for (i=0; i<ngroups; i++) {
		if (i>900) break;
                g = &groups[i];
                if (g->lastupto > g->upto) g->lastupto = g->upto;
                if (g->lasttime == 2) {
                        g->lastupto = g->upto;
                        g->lasttime = lib_gmtime();
                }
                fprintf(f,"group %s %d %d %d\n",
                        g->name,g->lasttime,g->upto,g->lastupto);
        }
        fclose(f);
}
int user_read(char *xuser)
{
        FILE *f;
        static int done;
        char bf[BFSZ];
        char *s;
        Ginfo *g;
	char user[BFSZ];

	ncpy(user,xuser,200);
	s = strchr(user,':'); 
	if (s!=NULL) *s = 0;

        
	imsg("user_read %d (%.80s)\n",strlen(user),user);
	if (strlen(user)==0) return FALSE;
        if (done) return TRUE;
        imsg("user_read_doing()\n");
        done = TRUE;
        f = fopen(user_file(user),"r");
        if (f==NULL) {
                imsg("Could not read user (%s) file (%s) %s\n",user,user_file(user),strerror(errno));
                return FALSE;
        }
        for (;!feof(f);) {
                if (fgets(bf,BFSZ-10,f)==NULL) break;
                s = strtok(bf," "); if (s==NULL) continue;
                uinfo[nuinfo] = strdup(s);
                if (strcmp(uinfo[nuinfo],"group")==0) {
                        g = &groups[ngroups];
                        s = strtok(NULL," \n"); if (s==NULL) continue;
                        g->name = strdup(s);
                        imsg("name = %s\n",s);
                        s = strtok(NULL," \n"); if (s==NULL) continue;
                        g->lasttime = atoi(s);
                        imsg("lasttime = %s\n",s);
                        s = strtok(NULL," \n"); if (s==NULL) continue;
                        g->upto = atoi(s);
                        /* imsg("Read upto %d\n",g->upto);*/
                        s = strtok(NULL," \n"); if (s==NULL) continue;
                        g->lastupto = atoi(s);

                        if (g->lasttime == 1) {
                                g->curupto = g->upto;
                                g->lasttime = lib_gmtime();

                        }

                        ngroups++;
			if (ngroups+10>MAX_SUB) break;
                } else {
                        s = strtok(NULL,"\n");
                        if (s==NULL) s = "";
                        uinfo_val[nuinfo++] = strdup(s);
			if (nuinfo>90) break;
                }
        }
        fclose(f);
	return TRUE;
}
void user_set(char *var, char *val)
{
        int i;
        for (i=0; i<nuinfo; i++) {
                if (strcmp(uinfo[i],var)==0) {
                        uinfo_val[i] = strdup(val);
                        return;
                }
        }
        uinfo[nuinfo] = strdup(var);
        uinfo_val[nuinfo++] = strdup(val);      
}
char *user_get(char *s)
{
        int i;
        for (i=0; i<nuinfo; i++) {
                if (strcmp(uinfo[i],s)==0) return uinfo_val[i];
        }
        return "";
}
void group_fetchone(int g);
void group_fetch(void)
{
        int i;
        char bf[10000];
        char *s;
        for (i=0; i<ngroups; i++) {
                group_fetchone(i);
        }
        user_write(utag); 
        
        strcpy(bf,"");
        s = bf;
        for (i=0; i<ngroups; i++) {
                sprintf(s,"<option value=\"%s\">%s</option>\n",groups[i].name,groups[i].name);
                s += strlen(s);
        }
        var_set("unsub_list",bf);
}
void group_fetchone(int g)
{       /*  211 1 2 2 test.1 selected */                            
        char *s;
        imsg("Fetching group %s\n",groups[g].name);
        tcp_printf(chan,"GROUP %s",groups[g].name);
        if (!read_status()) { zmsg("No such group (%s) %s",groups[g].name,nntp_status); return;	}
        imsg("Status %s\n",nntp_status);
        s = strtok(nntp_status," \t\n"); if (s==NULL) return;
        s = strtok(NULL," \t\n"); if (s==NULL) return;
        groups[g].total = atoi(s);
        s = strtok(NULL," \t\n"); if (s==NULL) return;
        s = strtok(NULL," \t\n"); if (s==NULL) return;
        groups[g].curupto = atoi(s);                    
        groups[g].upto = atoi(s);                       
        /* imsg("age %d\n",lib_gmtime() - groups[g].lasttime);*/
        
}
int tcp_printf(int chan, char * arg_list,...)
{
        va_list arg_ptr;
        char *format;
        char output[5000];
        va_start(arg_ptr, arg_list);
        format = arg_list;
        vsprintf(output, format, arg_ptr);
        strcat(output,"\r\n");
        nntp_write_s(chan,output,strlen(output));
        return TRUE;
}
int nntp_check(char *user, char *pass, char *etxt)
{
        if (!open_status()) {zmsg("News host not responding: %s",nntp_status); return FALSE;}
        tcp_printf(chan,"AUTHINFO USER %s\015\012",user);
        if (!read_status()) { 
		ncpy(etxt,nntp_status,100);
		imsg("Login user failed %s\n",etxt);
		return FALSE;
	}
        tcp_printf(chan,"AUTHINFO PASS %s\015\012",pass);
        if (!read_status()) { 
		ncpy(etxt,nntp_status,100);
		imsg("Login pass failed %s\n",etxt);
		return FALSE;
	}
        return TRUE;
}
int pop_check(char *user, char *pass, char *pop, char *etxt)
{
        char xpop[BFSZ];
        int p=-1;
        int r=FALSE;
        imsg("pop_check (%s)\n",user);
        ncpy(xpop,pop,BFSZ-1);
        if (!ini_true(I_POP_AUTHENT)) {
                if (strlen(xpop)>0) strcpy(xpop,"");
        }
/*      if (isdigit(pop)) { strcpy(etxt,"POP Host must be given by name not ip number");        goto done; }*/
        strcat(xpop,":110");
        if (strlen(ini_get(I_POP_HOST))>0) strcpy(xpop,ini_get(I_POP_HOST));
        imsg("pop_check1 (%s)\n",user);
        if (strlen(user)==0) { strcpy(etxt,"Please enter a user name");         goto done; }
        imsg("pop_check2 (%s)\n",user);
        if (strlen(pass)==0) { strcpy(etxt,"Please enter your pop password");   goto done; }
        imsg("pop_check3 (%s) (%s)\n",user,xpop);
        if (strlen(xpop)<5) 
                return nntp_check(user,pass,etxt);

        imsg("pop_check4 (%s)\n",user);
        if (strchr(xpop,':')==NULL) strcat(xpop,":110");
        imsg("Open %s\n",xpop);
        p = nntp_open(xpop);
        if (p<0) { strcpy(etxt,"Could not connect to pop host, please try again later");        goto done; }
        nntp_setblock(p,TRUE); /* Set to blocking IO */
        imsg("read pop\n");
        if (!read_pop(p)) { sprintf(etxt,"Login to POP server failed %s",nntp_status);  goto done; }
        imsg("read pop1 %s\n",nntp_status);
        if (!tcp_printf(p,"USER %s",user)) { strcpy(etxt,"Error writing to POP server, please try later");      goto done; }
        imsg("read pop2 %s\n",nntp_status);
        if (!read_pop(p)) { sprintf(etxt,"Login to POP server failed %s",nntp_status);  goto done; }
        if (!tcp_printf(p,"PASS %s",pass)) { strcpy(etxt,"Error writing to POP server, please try later");      goto done; }
        imsg("read pop3 %s\n",nntp_status);
        if (!read_pop(p)) { sprintf(etxt,"Login to POP server failed %s",nntp_status);  goto done; }
        r = TRUE;
done:
        if (p>=0) {
                tcp_printf(p,"QUIT");
                nntp_close(p);
        }
        return r;       
}
void set_id(void)
{
        char bf[BFSZ];
        sprintf(bf,"%d",lib_gmtime());
        var_set("loginid",bf);
}
void f_login(void)
{
        char bf[BFSZ];

        if (ini_true(I_WEB_LOGIN)) {
                ncpy(thisuser,mygetenv("REMOTE_USER"),BFSZ-1);
		imsg("f_login (%s) calling r_login \n",thisuser);
                r_login(FALSE);
                return;
        }

        tpl_init();
	var_set("togroup",either_find("togroup"));
        set_id();
        tpl_show("login.tpl");
}
void f_search(void)
{
        tpl_init();
        tpl_show("search.tpl");
/*
        if (!show_top("fsearch","Search Entire News Database Using: DNEWS Full Text Search Engine"))
                printf("<h1> Search All News Items</h1>"); 
        printf("<form method=get action=\"%s\"> \n",path_script);
        printf(" <input type=hidden name=\"cmd\" value=\"r_search\"> \n");
        printf(" <input type=hidden name=\"from\" value=\"1\"> \n");
        printf(" <input type=hidden name=\"to\" value=\"20\"> \n");
        printf("Key Words: <input name=\"key\" size=40 > <br>\n");
        printf("<input type=submit name=\"action\" value=\"Search\" >\n");
        printf("</form>\n");
        printf("<p>\n");
        printf("A higher weighting\n");
        printf("is given to words early in your list of key words.  \n");
        printf("Some common words like 'and' may return '0' matches, this\n");
        printf("is normal, these are not kept in the index as they have\n");
        printf("no search value.<br>\n");
        show_end("fsearch");
*/
}
void f_find(void)
{
        tpl_init()              ;
        tpl_show("xsearch.tpl");
}
void f_find_xold(void)
{
        if (!show_top("ffind","Search News Group Headers"))
                printf("<h1> Search headers in %s </h1>",query_find("group")); 
        printf("<form method=get action=\"%s\"> \n",path_script);
        printf(" <input type=hidden name=\"cmd\" value=\"r_find\"> \n");
        printf(" <input type=hidden name=\"group\" value=\"%s\"> \n",query_find("group"));
        printf("Search String: <input name=\"key\" size=40 > <br>\n");
        printf("<input type=submit name=\"action\" value=\"Search\" >\n");
        printf("</form>\n");
        printf("<p>\n");
        printf("The search is performed on the headers in the news group.\n");
        printf("It is not case sensitive.  If you give several words they\n");
        printf("will only match if the same 'phrase' appears in the news headers<br>\n");
        show_end("ffind");
}
void cmd_search_up(void)
{
        page_from = atoi(query_find("from_up"));
        page_to = atoi(query_find("to_up"));
        r_search();
}
void cmd_search_down(void)
{
        page_from = atoi(query_find("from_down"));
        page_to = atoi(query_find("to_down"));
        r_search();
}
int form_date(char *s)
{
	int x = atoi(s);
	if (strlen(s)==0) return 0;
	if (x < -9998) return 0;
	return (int) time(NULL)  + (x * 3600*24);
}
void r_search(void)  /* from=nnn   max=nnn*/
{
        char bf[BFSZ];
        int from = atoi(query_find("from"));
        int to = atoi(query_find("to"));
        char key[BFSZ],xkey[BFSZ],zkey[BFSZ];
        char *s;
        int total;
	char op[BFSZ];
        int i;
        char *kw[100];
        int nkw;
        int matches[100];
	int xsince,xbefore;
	char gwild[BFSZ];
	char stype[BFSZ];
	int search_match;
        if ((page_from!=0) || (page_to!=0)) {
                from = page_from; to = page_to;
        }
        if (from<0) {to -= from; from = 0;}

        ncpy(key,query_find("key"),400);
        imsg("r_search %d-%d (%s)\n",from,to,key);
        strcpy(zkey,key);
        s = strtok(key,",+ \t\n");
        strcpy(xkey,"");
        for (nkw=0;s!=NULL;) {
                strcat(xkey,s);
                kw[nkw++] = strdup(s);
                s = strtok(NULL,",+ \t\n");
                if (s!=NULL) strcat(xkey,",");
        }

        if (!open_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}
	
	/* New form fields in dnewsweb/dnews 5.3
		search_groups
		search_since
		search_before
		search_match
		search_sort (date,score,group)
	*/
	var_set("search_groups",query_find("search_groups"));
	var_set("search_since",query_find("search_since"));
	var_set("search_before",query_find("search_before"));
	var_set("search_match",query_find("search_match"));
	var_set("search_sort",query_find("search_sort"));

	ncpy(gwild,query_find("search_groups"),BFSZ-10);
	ncpy(stype,query_find("search_sort"),BFSZ-10);
	xsince = form_date(query_find("search_since"));
	xbefore = form_date(query_find("search_before"));
	search_match = FALSE;
	if (strlen(query_find("search_match"))>0) search_match = TRUE;

	strcpy(op,"");
	if (strlen(gwild)>0) {sprintf(bf,"groups=%.200s ",gwild); strcat(op,bf);}
	if (strlen(stype)>0) {sprintf(bf,"sort=%.200s ",stype); strcat(op,bf);}
	if (xsince!=0) {sprintf(bf,"since=%d ",xsince); strcat(op,bf);}
	if (xbefore!=0) {sprintf(bf,"before=%d ",xbefore); strcat(op,bf);}
	if (search_match) {strcat(op,"match=and ");}
	sprintf(bf,"xdsearch %d-%d %s %s\015\012",from,to,xkey,op); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}

        s = strchr(nntp_status,':');
        if (s!=NULL) total = atoi(s+1);
        s = strchr(s+1,':');
        if (s!=NULL) s = strtok(s,": \015\012");
        for (i=0;(s!=NULL) && (i<nkw);i++) {
                matches[i] = atoi(s);
                s = strtok(NULL," \015\012");
        }
        
        if (read_xover()) var_set("no_match","bazil");
        show_xover();
        tpl_init();
        var_set("key",query_find("key"));
        sprintf(bf,"%d",total);
        var_set("total_matches",bf);
        strcpy(bf,"");
        for (i=0; i<nkw; i++) {
		if (i!=0) strcat(bf,", ");
		sprintf(bf+strlen(bf),"%s %d",kw[i],matches[i]);
	}
        var_set("summary",bf);
        search_result = TRUE;
        tpl_init_sbar(from,to,total,zkey);
        tpl_show("results.tpl");


/*      show_sbar(from,to,total,zkey);
        show_search();
        show_sbar(from,to,total,zkey);

        show_end("search");
*/
        sprintf(bf,"quit\015\012"); nntp_write_s(chan,bf,strlen(bf)); 
        read_status(); /* Wait for the channel to close */
} 
int do_authent(void)
{
        char bf[BFSZ];
        char dom[BFSZ];
        char user[BFSZ];
        char pass[BFSZ];
	char fromip[BFSZ];
	char etext[BFSZ];
        ncpy(dom,mygetenv("REMOTE_ADDR"),BFSZ-1);
        ncpy(user,mygetenv("REMOTE_USER"),BFSZ-1);
        if (strlen(utag)>0) {
                if (islogin()) {
                        ncpy(user,guser,400);
                }
        }
	if (strlen(thispass)>0) if (ini_true(I_WEB_LOGIN)) {
		if (strlen(user)>0) if (ini_true(I_WEB_LOGIN_NOCHECK)) return TRUE;
		ncpy(pass,thispass,400);
		if (nntp_check(user,pass,etext)) return TRUE;	
		return FALSE;
	}
	if (ini_true(I_AUTH_NNTP)) {
		ncpy(pass,user_get("nntp_pass"),400);
		if (nntp_check(user,pass,etext)) return TRUE;	
		return FALSE;
	}

        strcpy(pass,ini_get(I_TELLNEWS_PASS));
        if (strlen(pass)==0) return TRUE;

        strcpy(fromip,ini_get(I_FROM_IP));
	if (strlen(fromip)>0) ncpy(dom,fromip,400);

        if (strlen(user)==0) {
		strcpy(user,"(none)");
		if (strlen(ini_get(I_DEFAULT_USER))>0) {
			strcpy(user,ini_get(I_DEFAULT_USER));
		}
	}
        if (strlen(dom)==0) strcpy(dom,"(none)");
        imsg("Authenticating Domain (%s) User (%s) \n",dom,user);
        sprintf(bf,"xdauthent %s %s %s\015\012",dom,user,pass); nntp_write_s(chan,bf,strlen(bf)); 
 imsg("xdauthent %s %s %s\n",dom,user,pass); 
        return read_status(); 
}

int do_latest_authent(void) {
        char dom[BFSZ];
        char user[BFSZ];
        char pass[BFSZ];
        char fromip[BFSZ];
        char bf[BFSZ];

        if (strlen(auth_username)==0) return FALSE;
        ncpy(user,auth_username,BFSZ-10);

        ncpy(pass,ini_get(I_TELLNEWS_PASS),BFSZ-10);
        if (strlen(pass)==0) return FALSE;

        ncpy(dom,ini_get(I_NEWSHOST),BFSZ-10);
        ncpy(fromip,ini_get(I_LATEST_IP),BFSZ-10);
        if (strlen(fromip)>0) ncpy(dom,fromip,BFSZ-10);
        
        if (strlen(dom)==0) ncpy(dom,"(none)",BFSZ-10);
        imsg("do_latest_authent: Authenticating Domain (%s) User (%s) \n",dom,user);
        sprintf(bf,"xdauthent %s %s %s\015\012",dom,user,pass); nntp_write_s(chan,bf,strlen(bf)); 
        imsg("do_latest_authent: xdauthent %s %s %s\n",dom,user,pass); 
        return read_status(); 
}

int group_readonly(char *group) {
    char bf[BFSZ];
    int ret=FALSE;
    sprintf(bf,"post\r\n"); nntp_write_s(chan,bf,strlen(bf)); 
    if (!read_status()) emsg("problem trying assess group postability\n");
    else {
        sprintf(bf,"Newsgroups: %s\r\n",group); nntp_write_s(chan,bf,strlen(bf));
        sprintf(bf,"From: can.i@post\r\n",group); nntp_write_s(chan,bf,strlen(bf));
        sprintf(bf,"Subject: testing postability\r\n.\r\n",group); nntp_write_s(chan,bf,strlen(bf));
        read_status();
        ret=(atoi(nntp_status)==480);
    }
    if (instr!=NULL) {
	    str_free(instr); /*brian789*/
	    instr=NULL;
    }
    return ret;
}

void f_follow(int follow)
{
        char bf[BFSZ];
        int item;
	

        if (ini_true(I_POST_REQUIRE_LOGIN)) {
                if (!islogin()) {
                        imsg("Sorry user isn't logged in\n");
                        sprintf(bf,"Sorry, you must login before posts can be accepted");
                        var_set("login_error",bf);
                        set_id();
                        tpl_show("login.tpl");
                        return;
                }
        }

        if (follow) {
                item = atoi(query_find("item"));
                if (item==0) item = atoi(query_find("xrelated"));
                ncpy(group,query_find("group"),BFSZ-1);
                if (!group_allow(group)) {zmsg("Cannot read that group"); return;}
                if (!open_status()) {zmsg("News host not happy %s",nntp_status); return;}
                if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}
                if (ini_true(I_POST_LOGIN)) {
		if (group_readonly(group)) { /* brian456*/
		    imsg("read only access to newsgroup %s showing login.tpl\n",group);
		    tpl_show("login.tpl");
		    return;
		};
		}
		sprintf(bf,"group %s\015\012",group); nntp_write_s(chan,bf,strlen(bf)); 
                if (!read_status()) {zmsg("News host group: %s",nntp_status); return;}
                sprintf(bf,"article %d\015\012",item); nntp_write_s(chan,bf,strlen(bf)); 
                if (!read_status()) {zmsg("News host article failed: %s",nntp_status); return;}
                read_xover();
        } else if (ini_true(I_POST_LOGIN)) {
	    ncpy(group,query_find("group"),BFSZ-1);
	    if (!group_allow(group)) {zmsg("Cannot read that group"); return;}
            /* brian456 - why? */
	    /*if (!open_status()) {zmsg("News host not happy %s",nntp_status); return;}*/
	    /* if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}*/
	    if (group_readonly(group)) {
	        imsg("read only access to newsgroup %s showing login.tpl\n",group);
		tpl_show("login.tpl");
		return;
	    };
	}

        ncpy(group,query_find("group"),BFSZ-1);
        if (!group_allow(group)) return;

        if (follow) {
                show_article1();
        }

        if (!follow) strcpy(subject,"");
        if (follow) {
                ncpy(bf,subject,400);
                strlwr(bf);
                if (strstr(bf,"re:")==NULL) {
                        ncpy(bf,subject,400);
                        sprintf(subject,"Re: %s",bf);   
                }
                if (ini_true(I_NON_ASCII)) ncpy(subject,rfc1522s(subject),BFSZ-10);
		var_set("h_subject",value_encode(subject));
        }
        user_read(utag);
	if (ini_true(I_NON_ASCII))
	{
	    var_set("from_name",rfc1522s(user_get("name")));
	    var_set("from",rfc1522s(user_get("reply")));
	}
	else {
	    var_set("from_name",user_get("name"));
	    var_set("from",user_get("reply"));
	}
        if (strlen(user_get("reply"))==0) {
		if (!ini_true(I_FROM_FORCE)) {
			strcpy(bf,real_from(""));
			var_set("from",bf);
		}
        }
	if (ini_true(I_FROM_WEB_LOGIN)) {
		sprintf(bf,"%s@%s",mygetenv("REMOTE_USER"),ini_get(I_POST_DOMAIN));
		var_set("from",bf);
		sprintf(bf,"%s",mygetenv("REMOTE_USER"));
		var_set("from_name",bf);
	}
        if (follow) tpl_show("follow.tpl");
        else tpl_show("post.tpl");
        if (follow) {
                sprintf(bf,"quit\015\012"); nntp_write_s(chan,bf,strlen(bf)); 
                read_status(); /* Wait for the channel to close */
        }
}
void show_xline(char *s)
{
        /* item subject from date messageid ref byte lines */
        char item[BFSZ];
        char subject[BFSZ];
        char from[BFSZ];
        char date[BFSZ];
        char msgid[BFSZ];
        char ref[BFSZ];
        char bytes[BFSZ];
        char lines[BFSZ];
        char score[BFSZ];
        char group[BFSZ];
	int i;

        strcpy(score,"NONE");
        strcpy(group,"NONE");
        strcpy(item,"");
        strcpy(subject,"");
        strcpy(from,"");
        strcpy(date,"");
        strcpy(msgid,"");
        strcpy(ref,"");
        strcpy(bytes,"");
        strcpy(lines,"");
	s = xstrtok(s,"\t\015\012"); if (s==NULL) goto done;
        ncpy(item,s,BFSZ-1);
        s = xstrtok(NULL,"\t\015\012"); if (s==NULL) goto done;
        ncpy(subject,s,BFSZ-1);
	if (ini_true(I_NON_ASCII)) ncpy(subject,rfc1522s(subject),BFSZ-10);
        s = xstrtok(NULL,"\t\015\012"); if (s==NULL) goto done;
        ncpy(from,s,BFSZ-1);
	if (ini_true(I_NON_ASCII)) ncpy(from,rfc1522s(from),BFSZ-10);
        s = xstrtok(NULL,"\t\015\012"); if (s==NULL) goto done;
        ncpy(date,s,BFSZ-1);
        s = xstrtok(NULL,"\t\015\012"); if (s==NULL) goto done;
        ncpy(msgid,s,BFSZ-1);
        s = xstrtok(NULL,"\t\015\012"); if (s==NULL) goto done;
        ncpy(ref,s,BFSZ-1);
        s = xstrtok(NULL,"\t\015\012"); if (s==NULL) goto done;
        ncpy(bytes,s,BFSZ-1);
        s = xstrtok(NULL,"\t\015\012"); if (s==NULL) goto done;
        ncpy(lines,s,BFSZ-1);
imsg("xover got %s %s\n",item,date);
        for (i=0; i<10 && s!=NULL; i++) {
                s = xstrtok(NULL,"\t\015\012"); if (s==NULL) goto done;
                if (strncmp(s,"fts_score:",10)==0) ncpy(score,s+11,10);
                if (strncmp(s,"fts_group:",10)==0) ncpy(group,s+11,80);
        }

done:;

        xover_add(item,subject,from,lines,date,ref,msgid,bytes);
        x_score[nitem-1] = strdup(score);
        x_group[nitem-1] = strdup(group);
}
char *xstrtok(char *line, char *in)
{
        static int end=FALSE;
        static char *last;
        char *s;
        if (line==NULL) {
                line = last;
                if (end) return NULL;
        } else end=FALSE;

        s = strchr(line,'\t');
        if (s==NULL) {
                end = TRUE;
                s = strchr(line,'\015');
                if (s!=NULL) *s = 0;
                return line;
        }
        *s = 0;
        last = s+1;
        return line;
}
char *lib_nore(char *s)
{
        static char bf[BFSZ];
        ncpy(bf,s,BFSZ-1);
        strlwr(bf);
        s = bf;
        if (strncmp(s,"re:",3)==0) s += 3;
        if (*s==' ') s++;
        return s;
}
void xover_add(char *item, char *subject, char *from, char *lines, char *date, char *ref, char *mid, char *bytes)
{
        if (strcmp(item,".")==0) return;
        if (nitem>1800) return;
        x_item[nitem] = atoi(item);
        x_subject[nitem] = strdup(head_decode(subject));
        x_subjectsrt[nitem] = strdup(lib_nore(subject));
        x_from[nitem] = strdup(head_decode(from));
        x_date[nitem] = strdup(date);
        x_lines[nitem] = strdup(lines);
        x_bytes[nitem] = strdup(bytes);
        x_ref[nitem] = strdup(ref);
        x_mid[nitem] = strdup(mid);
        nitem++;
}
int the_cmp(const void *elem1, const void *elem2  )
{
    int *a = (int *) elem1;
    int *b = (int *) elem2;
    return x_item[*a] - x_item[*b];
}



int sort_the_xover(void)
{
    int *p;
    char *s;
    char **x;
    int *xi;
    int i;
    p = mymalloc(sizeof(int)*nitem+1);
    x = mymalloc(sizeof(char *)*nitem+1);
    xi = mymalloc(sizeof(int)*nitem+1);


    for (i=0; i<nitem; i++) p[i] = i;
    if (nitem>1) qsort(p,nitem,sizeof(int),the_cmp);

    for (i=0; i<nitem; i++) xi[i] = x_item[p[i]];
    for (i=0; i<nitem; i++) x_item[i] = xi[i];
    for (i=0; i<nitem; i++) x[i] = x_subject[p[i]];
    for (i=0; i<nitem; i++) x_subject[i] = x[i];
    for (i=0; i<nitem; i++) x[i] = x_subjectsrt[p[i]];
    for (i=0; i<nitem; i++) x_subjectsrt[i] = x[i];
    for (i=0; i<nitem; i++) x[i] = x_from[p[i]];
    for (i=0; i<nitem; i++) x_from[i] = x[i];
    for (i=0; i<nitem; i++) x[i] = x_date[p[i]];
    for (i=0; i<nitem; i++) x_date[i] = x[i];
    for (i=0; i<nitem; i++) x[i] = x_lines[p[i]];
    for (i=0; i<nitem; i++) x_lines[i] = x[i];
    for (i=0; i<nitem; i++) x[i] = x_bytes[p[i]];
    for (i=0; i<nitem; i++) x_bytes[i] = x[i];
    for (i=0; i<nitem; i++) x[i] = x_ref[p[i]];
    for (i=0; i<nitem; i++) x_ref[i] = x[i];
    for (i=0; i<nitem; i++) x[i] = x_mid[p[i]];
    for (i=0; i<nitem; i++) x_mid[i] = x[i];

    myfree(xi);
    myfree(x);
    myfree(p);

}
int xover_cmp(const void *a,const void *b)
{
        int *aa = (int *) a;
        int *bb = (int *) b;
        if (x_f[*aa] < x_f[*bb]) return -1;
        if (x_f[*aa] > x_f[*bb]) return 1;
        return 0;
}
int xover_cmp_old(const void *a,const void *b)
{
        int *aa = (int *) a;
        int *bb = (int *) b;
        return strcmp(x_subjectsrt[*aa],x_subjectsrt[*bb]);
}
void xover_showord(void)
{
        int p[MAX_ITEMS]; 
        int i,ii;
        for (i=0; i<nitem; i++) p[i] = i;

        if (dosort) qsort(p,nitem,sizeof(int),xover_cmp);
        printf("<ul>\n");
        for (i=0; i<nitem; i++) {
                ii = p[i];
                printf("<li><a href=\"%s?cmd=article&group=%s&item=%d\">",path_script,towww(group),x_item[ii]);
                printf("%s</a> - %s (%s) <br>\n",value_encode(x_subject[ii]), email_name(x_from[ii]),x_lines[ii]);
        }
        printf("</ul>\n");

}
void r_find(void)  /* from=nnn   max=nnn*/
{
        char bf[BFSZ];
        char find[BFSZ];

        ncpy(find,query_find("key"),BFSZ-1);
        ncpy(group,query_find("group"),BFSZ-1);
        if (!group_allow(group)) return;

        if (!open_status()) {zmsg("News host not responding1: %s",nntp_status); return;}
        if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}
        sprintf(bf,"group %s\015\012",group); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("News host not responding2: %s",nntp_status); return;}
        sprintf(bf,"xdfind 1- %s\015\012",lib_encode(find)); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("News host not responding3: %s",nntp_status); return;}
        if (read_xover()) var_set("no_match","bazil");
	show_xover();

        tpl_init();
        tpl_set_buttons();

        var_set("keywords",find);
        tpl_show("xresults.tpl");
/*      
        if (!show_top("find"," Search results %s ",group))
                printf("<h1> Search Results: %s</h1>",group); 
        show_xbar();

        xover_showord();
        show_xbar();

        show_end("find");

*/
        sprintf(bf,"quit\015\012"); nntp_write_s(chan,bf,strlen(bf)); 
        read_status(); /* Wait for the channel to close */
}
void cmd_up(void)
{
        page_from = atoi(query_find("from_up"));
        if (page_from!=0) if (page_from<0) page_from=1;
        r_xover();
}
void cmd_down(void)
{
        page_from = atoi(query_find("from_down"));
        if (page_from!=0) if (page_from<0) page_from=1;
        r_xover();
}
void cmd_latest(void)
{
        page_from = -1;
        r_xover();
}
static int xrelated;
void cmd_related(void)
{
        xrelated = atoi(query_find("xrelated"));
        r_xover();
}
int require_login(void)
{
        if (ini_true(I_REQUIRE_LOGIN) || ini_true(I_WEB_LOGIN)) {
                if (!islogin()) {
                        do_login("Sorry, you are not logged in");
                        return TRUE;
                }
        }
        return FALSE;
}
void r_xover(void)  /* from=nnn   max=nnn*/
{
        char bf[BFSZ];
        char rsubject[BFSZ];
        char rmsgid[BFSZ];
        int from = atoi(query_find("from"));
        int max = atoi(query_find("max"));
        int to,xfrom,xto,lastfrom;
	int group_n;
        char *s;
	int upto;
	int maxto = 0;
        int nloop = 0;
        int fwd = FALSE;
        int related;
	int minfrom;
dmsg("called r_xover");

        if (require_login()) return;
        if (page_from!=0) from = page_from;
        if (from<0) from = 0;
        related = atoi(query_find("related"));
        if (xrelated>0) related = xrelated;
        if (strcmp(query_find("forward"),"TRUE")==0) fwd = TRUE;
        
        ncpy(group,either_find("group"),BFSZ-1);
        if (!group_allow(group)) return;

	if (!ini_true(I_SUBSCRIBE_MANUAL)) {
		if (strlen(utag)>0) {
		        user_read(utag);
		        group_add(query_find("group"));
		        user_write(utag);
		}
	}

        if (max==0) max = PAGESIZE;
        if (max>1000) max = 1000;
        gmax = max;

dmsg("Wait for hello\n");
        if (!open_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}
	
	sprintf(bf,"group %s\015\012",group); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) { 
                imsg("%s",nntp_status);
                if (atoi(nntp_status)==411) {
                        zmsg("News host not responding: %s",nntp_status); return;
                }
                sprintf(bf,"Authenticaton required to read news group");
                if (strlen(ini_get(I_TELLNEWS_PASS))==0) {
                        sprintf(bf,"To read protected news groups, define tellnews_pass in dnewsweb.ini to match (work)/tellnews.pass on dnews");               
                }
                var_set("login_error",bf);
                set_id();
                tpl_show("login.tpl");                          
                return;
        }
        imsg("%s",nntp_status);
        if (related>0) {
                imsg("Searching for related items %d\n",related);
                sprintf(bf,"xover %d\015\012",related); nntp_write_s(chan,bf,strlen(bf)); 
                if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
                read_xover();

		/* find first message-id in the references */
                s = get_line(instr);
		if (s==NULL) {zmsg("News host not responding thread: %s",nntp_status); return;}
                s = xstrtok(s,"\t");
                if (s!=NULL) s = xstrtok(NULL,"\t");	/* skip nntp response code*/
                if (s!=NULL) {				/* get subject*/
                        strlwr(s);
                        if (strncmp(s,"re:",3)==0)  s += 3; 
                        if (*s == ' ') s++;
                        ncpy(rsubject,s,BFSZ-1);
                }
                if (s!=NULL) s = xstrtok(NULL,"\t");	/*/ skip from*/
                if (s!=NULL) s = xstrtok(NULL,"\t");	/*/ skip date*/
                if (s!=NULL) s = xstrtok(NULL,"\t");	/*/ skip message-id*/
                if (s!=NULL) ncpy(rmsgid,s,BFSZ-1);	/*/ get the message-id of the root thread*/

                str_clear(instr);

                
                sprintf(bf,"xhdr references %d\015\012",related); nntp_write_s(chan,bf,strlen(bf)); 
                if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
                read_xover();
                s = get_line(instr);
                ncpy(bf,s,BFSZ-200);
                imsg("xhdr response %.90s\n",bf);
                s = strtok(bf," \r\n");
                if (s!=NULL) s = strtok(NULL," \r\n");	/* skip nntp response code*/
                if (s!=NULL) if (s[0]=='<') ncpy(rmsgid,s,BFSZ-10);
                imsg("Original mid (%s)\n",rmsgid);
                imsg("xhdr full stop %.90s\n",nntp_status);
                str_clear(instr);

                sprintf(bf,"xdfind 1- %s %s\015\012",lib_encode(rsubject),lib_encode(rmsgid)); nntp_write_s(chan,bf,strlen(bf)); 
                imsg("Searching for related items (%s) \n",bf);
                if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        } else {
                group_n = atoi(get_word(nntp_status,1));
                group_from = xfrom = atoi(get_word(nntp_status,2));
		imsg("group command, group_from = %d\n",group_from);
                group_to = xto = atoi(get_word(nntp_status,3));
		minfrom = group_to;
                if (strlen(query_find("from"))==0)  if (from==0) from = xto-max;
                if (from<xfrom) from = xfrom;
                to = from+max;
                gfrom = from; gto = to;
		upto = gto;
		
again:
                imsg("xfrom=%d xto =%d max=%d to=%d  %d-%d\n",xfrom,xto,max,to,gfrom,gto);
                imsg("xover %d-%d\n",gfrom,gto); 
                sprintf(bf,"xover %d-%d\015\012",gfrom,gto); nntp_write_s(chan,bf,strlen(bf)); 
                if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        }
	if (maxto<gto) maxto = gto;
	if (minfrom>gfrom) minfrom = gfrom;
        var_set("group_to",int_str(maxto));
	var_set("group_from",int_str(minfrom));
        read_xover();
        show_xover();
        lastfrom = gfrom;
        if (related==0) if (nitem<max) {
          if (fwd) {
                gfrom = gto;
                gto += max;
		upto = gto;
                nloop++;
                if (nloop<100) if (gfrom<=group_to) goto again;
          } else {
                gto = gfrom-1;
                if (gfrom>group_from) gfrom -=max;
                if (gfrom<group_from) gfrom = group_from;
                if (gfrom!=lastfrom) {
                        goto again;
                }
          }
        }
	sort_the_xover();
	gto = upto;
        if (related>0) sprintf(bf,"Related items in %s",group);
        else sprintf(bf,"Items in %s",group);

        var_set("group_n",int_str(group_n));
	gto = maxto;
	gfrom = minfrom;
        tpl_set_buttons();
        tpl_show("items.tpl");
        sprintf(bf,"quit\015\012"); nntp_write_s(chan,bf,strlen(bf)); 
        read_status(); /* Wait for the channel to close */
} 
void r_listall(void)  /* from=nnn   max=nnn*/
{
        char bf[BFSZ];
        ncpy(group,query_find("group"),BFSZ-1);

        if (!open_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}
        sprintf(bf,"xdlist %s\015\012",group); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {
                printf("Sorry, this server does not support the nntp DLIST command<br>");
                printf("Try DNEWS 2.5 or later or possibly you need to give your web server access to dnews with no password restrictions<br>%s<br>",nntp_status);
                return;
        }
        read_xover();
        tpl_init();
        tpl_show("list.tpl");
        sprintf(bf,"quit\015\012"); nntp_write_s(chan,bf,strlen(bf)); 
        read_status(); /* Wait for the channel to close */
} 
void cmd_next(void)
{
        b_item = atoi(query_find("xrelated"))+1;
        r_article();
}
void cmd_last(void)
{
        b_item = atoi(query_find("xrelated"))-1;
        r_article();
}

/* brian's new next/previous in thread stuff */
void cmd_thread_both(int isup) ;
void cmd_thread_next(void) 
{
	cmd_thread_both(TRUE);
}
void cmd_thread_last(void) 
{
	cmd_thread_both(FALSE);
}
void cmd_thread_both(int isup) 
{
        char bf[BFSZ];
        char find[BFSZ];
        int np;
        char *p[1000];
	char *s;
	char rsubject[BFSZ];
	char rmsgid[BFSZ];
	int n;

        b_item = atoi(query_find("xrelated"));

        ncpy(find,query_find("key"),BFSZ-1);
        ncpy(group,query_find("group"),BFSZ-1);
        if (!group_allow(group)) return;

        if (!open_status()) {zmsg("News host not responding1: %s",nntp_status); return;}
        if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}
        sprintf(bf,"group %s\015\012",group); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("News host not responding2: %s",nntp_status); return;}
	sprintf(bf,"xover %d\015\012",b_item); nntp_write_s(chan,bf,strlen(bf));         

	if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
	read_xover();

	/* find first message-id in the references */
	s = get_line(instr);
	s = xstrtok(s,"\t");
	if (s!=NULL) s = xstrtok(NULL,"\t");	/* skip nntp response code*/
	if (s!=NULL) {		/* get subject*/
		strlwr(s);
		if (strncmp(s,"re:",3)==0)  s += 3; 
		if (*s == ' ') s++;
		ncpy(rsubject,s,BFSZ-1);
	}
	if (s!=NULL) s = xstrtok(NULL,"\t");	/*/ skip from*/
	if (s!=NULL) s = xstrtok(NULL,"\t");	/*/ skip date*/
	if (s!=NULL) s = xstrtok(NULL,"\t");	/*/ skip message-id*/
	if (s!=NULL) ncpy(rmsgid,s,BFSZ-1);	/*/ get the message-id of the root thread*/
	
	str_clear(instr);
	
	sprintf(bf,"xhdr references %d\015\012",b_item); nntp_write_s(chan,bf,strlen(bf)); 
	if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
	read_xover();
	s = get_line(instr);
	ncpy(bf,s,BFSZ-200);
	s = strtok(bf," \r\n");
	if (s!=NULL) s = strtok(NULL," \r\n");	/* skip nntp response code*/
	if (s!=NULL) if (s[0]=='<') ncpy(rmsgid,s,BFSZ-10);
	str_clear(instr);
	
	if (isup) {
		sprintf(bf,"xdfind %d- %s %s\015\012",b_item+1,lib_encode(rsubject),lib_encode(rmsgid)); nntp_write_s(chan,bf,strlen(bf)); 
	} else {
		sprintf(bf,"xdfind 1-%d %s %s\015\012",b_item-1,lib_encode(rsubject),lib_encode(rmsgid)); nntp_write_s(chan,bf,strlen(bf)); 
	}
	imsg("Thread Searching for related items (%s) \n",bf);
	if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        if (read_xover()) {
		sprintf(bf,"%d",b_item);
		var_set("xreated",bf);
		if (isup) var_set("msg","Sorry, no next item in that thread");
		else var_set("msg","Sorry, no previous item in that thread");
	        tpl_init_item();
		tpl_show("item_nomore.tpl");
		return;
	}
        s = get_line_nowrap(instr); 
	if (s==NULL) { zmsg("No xover data"); return;}
        for (n = -1;s!=NULL;) {
		n = atoi(s);
		if (n<0) break;
		if (isup) {
			if (n>b_item) break;
		} else { ;
		}
                s = get_line_nowrap(instr);
        }
	if (n<0) {
		zmsg("Sorry, no next item in that thread");
		return;
	}
	imsg("Found item %d\n",n);
	b_item = n;
        r_article();
}




void r_raw(void)
{
    char bf[BFSZ];
    int item = atoi(query_find("item"));
    if (require_login()) return;

    if (b_item>=0) item = b_item;
    ncpy(group,query_find("group"),BFSZ-1);
    imsg("r_raw() group=%s item=%d \n",group,item);
    if (!group_allow(group)) return;
    if (!open_status()) {zmsg("News host not responding: %s",nntp_status); return;}
    if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}
    sprintf(bf,"group %s\015\012",group); nntp_write_s(chan,bf,strlen(bf)); 
    if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
    var_set("item",int_str(item));
    sprintf(bf,"article %d\015\012",item); nntp_write_s(chan,bf,strlen(bf)); 
    if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
    read_xover();
    show_raw();
    sprintf(bf,"quit\015\012"); nntp_write_s(chan,bf,strlen(bf)); 
    read_status(); /* Wait for the channel to close */
}

void nobble_script(void) {
        /* code to nobble <script> </script> <applet> </applet> and <form> </form> tags */
        char *s;
        static String *tempstr;
        int inscript = FALSE;
        int inapp = FALSE;
        int inform = FALSE;
        int ascript,ajava,aform;

        ascript = ini_true(I_ALLOW_SCRIPT);
        ajava = ini_true(I_ALLOW_JAVA);
        aform = ini_true(I_ALLOW_FORM);

        imsg("nobble_script: disabled javascript=%d applets=%d forms=%d\n",!ascript,!ajava,!aform); 
        if (ascript&&ajava&&aform) return;
        
        s=str_s(instr);
        if (s==NULL) return;
        tempstr = str_new();
        str_copysn(tempstr,"");
        for(;*s!=0;s++) {
                if (inscript||inapp||inform) {
                        /* look for end tag */
                        if (*s!='<') {
                                str_adds(tempstr,s,1);
                                continue;
                        };
                        if (inscript) {
                            if(strncmpnc(s,"</script>",9)==0) {
                                        str_addsn(tempstr,"</script>\n <!--- --->\n");
                                        inscript=FALSE;
                                        s+=9;
                                        continue;
                                };
                        };
                        if (inapp) {
                            if(strncmpnc(s,"</applet>",9)==0) {
                                        str_addsn(tempstr,"</applet>\n <!--- --->\n");
                                        inapp=FALSE;
                                        s+=9;
                                        continue;
                                };
                        };
                        if (inform) {
                            if(strncmpnc(s,"</form>",7)==0) {
                                        str_addsn(tempstr,"</form>\n <!--- --->\n");
                                        inform=FALSE;
                                        s+=7;
                                        continue;
                                };
                        };
                        str_adds(tempstr,s,1);
                        continue;
                } else {
                        /* look for start tag */
                        if (*s!='<') {
                                str_adds(tempstr,s,1);
                                continue;
                        }
                        else {
                                /* check for possible <script <app or <form */
                                if (!ascript) if (strncmpnc(s,"<script",7)==0) {
                                        str_addsn(tempstr,"\nscript tag removed\n <!--- ");
                                        inscript=TRUE;
                                        continue;
                                }
                                if (!ajava) if(strncmpnc(s,"<app",4)==0) {
                                        str_addsn(tempstr,"\napp tag removed\n <!--- ");
                                        inapp=TRUE;
                                        continue;
                                }
                                if (!aform) if(strncmpnc(s,"<form",5)==0) {
                                        str_addsn(tempstr,"\nform tag removed\n <!--- ");
                                        inform=TRUE;
                                        continue;
                                }
                                str_adds(tempstr,s,1);
                                continue;
                        }
                }
        };
        /*imsg("nobble script: input: '%s'\n",str_s(instr));*/
        str_copy(instr,tempstr);
        /*imsg("nobble script: output: '%s'\n",str_s(instr));*/
}

void r_article(void)  /* from=nnn   max=nnn*/
{
        char bf[BFSZ];
        int first,last;
        int item = atoi(query_find("item"));
        if (require_login()) return;

        if (b_item>=0) item = b_item;
        ncpy(group,query_find("group"),BFSZ-1);
        imsg("r_article() group=%s item=%d \n",group,item);
        if (!group_allow(group)) return;

        if (!open_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}
        sprintf(bf,"group %s\015\012",group); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        /* status number first last name*/
        last = atoi(get_word(nntp_status,3));
        first = atoi(get_word(nntp_status,2));


        imsg("Group first=%d last=%d item %d\n",first,last,item);
        if (item<last) {
                sprintf(bf,"%s?cmd=article&group=%s&item=%d&utag=%s",path_script,towww(group),item+1,utage);
                var_set("item_next",bf);
        }
        if (item>first) {
                sprintf(bf,"%s?cmd=article&group=%s&item=%d&utag=%s",path_script,towww(group),item-1,utage);
                var_set("item_last",bf);
        }       
        var_set("item",int_str(item));

        sprintf(bf,"article %d\015\012",item); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        read_xover();
        nobble_script();
        show_article();
        sprintf(bf,"quit\015\012"); nntp_write_s(chan,bf,strlen(bf)); 
        read_status(); /* Wait for the channel to close */
}
/*

From: Bruce the Duck <removed@due.to.spam.com>
Newsgroups: alt.binaries.sounds.mp3.beatles
Subject: As requested - Rubber Soul - 05 - Think For Yourself.mp3 (5/7)
Date: Fri, 22 Oct 1999 13:23:11 -0400
Message-ID: <f50QOIX3AoNEkXWM0UM4FDBMjNEx@4ax.com>
X-Newsreader: Forte Agent 1.6/32.525
MIME-Version: 1.0
Content-Type: message/partial; id="<epwQODI1v4zyMKtdRRFsHKwjA3Wj@4ax.com>"; number=5; total=7
NNTP-Posting-Host: 12.21.199.102
X-Trace: 22 Oct 1999 13:24:52 -0400, 12.21.199.102
Organization: OneNet Communications News Hub
Lines: 6415


0wcrZl8Lm71gpW+KvPNpTJirkXqg7nWTFXIYeOo+QpgLEQRz8wZY9/lOiMkVi0ouK8lHUJLp90zl
/g+T9Cr6CzxIxXof/+vgzJuuYQa1nyiWZi7SsUX0wlqgctMnD5x5rgi93ZyyCIJTclwxsAUlzPL
SjIbe9X3qS3kr87qOXXpGFMZXbMzMDYaHk1MqSC0EE7qT/CF3l2wQGNtHuemIpNrElo2zjl5JMIP


If mime, then find this in first message.
  Content-Transfer-Encoding: base64
And this in each part header:
  Content-Type: message/partial; id="<15sQOM0Q6K94PP=MeT=yIjtOJW0L@4ax.com>"; number=1; total=8

*/

void r_parts(void)
{
        char *out;
        int nout;
	int r;
      	int sz=0;
	char tname[BFSZ];
        char bf[BFSZ];
        char bf2[BFSZ];
	char xbf[BFSZ];
	char xsubj[BFSZ];
	char fname[BFSZ];
	char content[BFSZ];
	int parti;
	int xparts[5000]; 
	int nfound=0;
	FILE *f;
        int item = atoi(query_find("item"));
	char subj[BFSZ];
	char *s;
	int n;
	int isbase64 = FALSE;
	int max;
	int i;
	int chunk;
	int xinit;
	int gotdata = FALSE;
	int upto;
	int partmax = atoi(query_find("partmax"));
	if (partmax>500) {
		emsg("Too many parts %d",partmax);
		return;
	}
	ncpy(subj,query_find("subj"),BFSZ-10);

	
	if (require_login()) return;

        if (b_item>=0) item = b_item;
        ncpy(group,query_find("group"),BFSZ-1);
        imsg("r_parts() group=%s item=%d partmax=%d, subj=(%s) \n",group,item,partmax,subj);
        if (!group_allow(group)) return;

        if (!open_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}
        sprintf(bf,"group %s\015\012",group); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        /* status number first last name*/
	ncpy(bf2,subj,400);
        sprintf(bf,"xdfind 1- %s\015\012",lib_encode(bf2)); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("News host not responding xdfind: %s",nntp_status); return;}
        if (read_xover()) var_set("no_match","bazil");

	for (i=0; i<=partmax; i++) xparts[i] = -1;
	
        s = get_line_nowrap(instr);
        for (;s!=NULL;) {
		/* */
		n = atoi(s);
		s = strtok(s,"\t");
		if (s!=NULL) {
			s = strtok(NULL,"\t");
			if (s!=NULL) {
				imsg("Found item %d subj %s\n",n,s);
				if (parts_subject(s,xsubj,fname,&parti,&max)) {
					if ((strcmpnc(xsubj,subj)!=0) || (max!=partmax)) {
						imsg("Wrong item part (%s) (%s) or max %d..%d\n",xsubj,subj,max,partmax);
					} else {
						if (xparts[parti]<0) nfound++;
						xparts[parti] = n;
					}
				} else {
					imsg("Invalid subject\n");
				}
			}
		}
                s = get_line_nowrap(instr);
        }
	sprintf(content,"application/octet-stream; name=\"%s\"",fname);

	if (nfound<partmax) {
		do_content();
                emsg("Only found %d of %d parts, sorry \n",nfound,partmax); 
		return;
	}
	
	sprintf(bf,"parts_%d.tmp",getpid());
	strcpy(tname,ini_work(bf));
	f = fopen(tname,"w");
	if (f==NULL) {
		do_content();
                emsg("Cannot write temp file %s %s \n",tname,strerror(errno)); 
		return;
	}
	xinit = FALSE;
	for (parti=1; parti<=partmax; parti++) {
		str_clear(instr);
		sprintf(bf,"body %d\015\012",xparts[parti]); nntp_write_s(chan,bf,strlen(bf)); 
		imsg("ask for body %d\n",xparts[parti]);
	        if (!read_status()) {zmsg("News host not responding body: %s",nntp_status); return;}
	        if (read_xover()) var_set("no_match","bazil");
		s = get_line_nowrap(instr);
		for (;s!=NULL;) {
			if (!xinit) {
				if (strncmpnc(s,"Content-Type: ",14)==0) {
					ncpy(content,s+14,200);
				}
				if (strcmpnc(s,"Content-Transfer-Encoding: base64")==0) {
					isbase64 = TRUE;
					imsg("This is a base64 message\n");
				}
				if (parti>1) if (isbase64) if (gotdata) if (strlen(s)==60) {
					imsg("Might be data again as it's the right length\n");
					xinit = TRUE;
				}
				if (!gotdata) if (isbase64) if (strlen(s)==0) {
					xinit = TRUE;
					imsg("Found start of base64 data\n");
				}
			}
			if (strcmp(s,"end")==0) {
				imsg("Found end\n");
				xinit = FALSE;
			}
			if (strcmp(s,"`")==0) {
				imsg("Found reverse quote\n");
				xinit = FALSE;
			}
			if (xinit) if (strlen(s)>0) {								
				fprintf(f,"%s\n",s);
				gotdata = TRUE;
			} 
			if (gotdata) if (*s==0) {
				imsg("Found blank line\n");
				xinit = FALSE;
			}
			if (strncmp(s,"begin ",6)==0) xinit = TRUE;
			sz += strlen(s);
		        s = get_line_nowrap(instr);
		}
	}
	fclose(f);

#ifdef FIX_STDOUT
        _setmode(_fileno(stdout),_O_BINARY);
#endif
	
	imsg("Image size encoded is %d bytes\n",sz);
 	out = mymalloc(sz+5000);
	nout = 0;

	f = fopen(tname,"r");
	if (f==NULL) {
		do_content();
                emsg("Cannot read temp file %s %s \n",tname,strerror(errno)); 
		return;
	}
	for (;!feof(f);) {
		if (fgets(bf,BFSZ-1,f)==NULL) break;
		s = strchr(bf,'\n'); if (s!=NULL) *s = 0;      
		if (isbase64) {
			n = decode_base64(bf,out+nout);
		} else {
			n = decode_uu(bf,out+nout);
		}
		if (n<0) {
			imsg("Odd n=%d\n",n);
			continue;
		}
                nout += n;
	}
	
	fclose(f);
	imsg("Now sending data to screen nout=%d\n",nout);
	done_content = TRUE;
	
	printf("Content-Type: %s\n",content);
	imsg("Content-Type: %s\n",content);
	printf("Content-Disposition: attachment; filename=\"%s\"\n",fname);
        printf("Content-length: %d\n",nout); 
	printf("\n");
	for (upto=0;nout>0;) {
		chunk = nout;
		if (chunk>4000) chunk = 4000;
		nout -= chunk;
		r = fwrite(out+upto,1,chunk,stdout);
		if (r!=chunk) {
			imsg("Wrote %d/%d bytes with fwrite %s\n",r,chunk,strerror(errno));
			break;
		}
		upto += chunk;
	}
	if (fflush(stdout)!=0) {
		imsg("Flush failed %s\n",strerror(errno));
	}
	imsg("file left %s\n",tname);
	remove(tname);	
}
char *post_template(char *xfname);

char *fix_crlf(char *s)
{
        int len;
        int wrap;
        char *bf;
        char *out;

        bf = malloc(strlen(s)*2+100);

        for (out=bf;*s!=0;s++) {
                if ((s[0]=='\r') && (s[1]!='\n')) {
                        *out++ = '\r';
                        *out++ = '\n';
                } else if ((s[0]!='\r') && (s[1]=='\n')) {
                        *out++ = '\r';
                        *out++ = '\n';
                } else {
                        *out++ = *s;            
                }
        }
        *out++ = 0;
        return bf;
}
/* chris to here */
void do_addbr(char *msg, char *out)
{
        int len;
        char *s;

        for (s=msg; (*s!=0); s++) {
                if (*s=='\n') {
                        *out++ = '<';
                        *out++ = 'b';
                        *out++ = 'r';
                        *out++ = '>';
                }
                *out++ = *s;
        }
        *out++ = 0;
}


int JLLgetindentonline(char *indent, char *readpos){
        int len = 0;
    int found = FALSE;
    while (found == FALSE){
        found = TRUE;
        if (readpos[len] == '\r' || readpos[len] == '\n' || readpos[len] == 0) 
            {*(indent + len) = 0; return len;}
        
        if (strncmp((readpos + len),"> ",2)==0)
            { found = FALSE;
            *(indent + len) = *(readpos + len);
            *(indent + len+1) = *(readpos + len+1);len += 2;}
        else if (strncmp((readpos + len),">",1)==0)
            { found = FALSE;
            *(indent + len) = *(readpos + len);len += 1;}
                if (len>195) break;
    }
    *(indent + len) = 0;
    return len;
}
int JLLgetindentlen(char *readpos){
        int len = 0;
    int found = FALSE;
    while (found == FALSE){
        found = TRUE;
        if (readpos[len] == '\r' || readpos[len] == '\n' || readpos[len] == 0) 
            { return len;}
        
        if (strncmp((readpos + len),"> ",2)==0)
            { found = FALSE;
            len += 2;}
        else if (strncmp((readpos + len),">",1)==0)
            { found = FALSE;
            len += 1;}
                if (len>195) break;
    }
    return len;
}

void JLLoutput(void (*outputfn)(char *), char *thisline){
     int sp;
     sp = strlen(thisline);
     if (thisline[sp] == ' ')
        thisline[sp] = 0;
     if (thisline[sp-1] == ' ')
        thisline[sp-1] = 0;
        outputfn(thisline);
}

int JLLprintword(char *readpos, char *indent, char *thisline, char *nextword, int wrap, int wordsfoundonline, void (*outputfn)(char *)){
        int thisline_len, nextword_len;
        nextword_len = strlen(nextword);
        if (nextword_len == 0) return wordsfoundonline;
        thisline_len = strlen(thisline);
        if (strlen(nextword) == 0) return wordsfoundonline;
    if (nextword_len + thisline_len > wrap || nextword_len + thisline_len > 380){
        if (thisline_len > JLLgetindentlen(thisline) ){
            JLLoutput(outputfn,thisline);
            wordsfoundonline = 0;
                strcpy(thisline, indent);
        }
        strcat(thisline, nextword);
                wordsfoundonline++;
        strcat(thisline," ");
                return wordsfoundonline;
                /*thisline_len = strlen(thisline);
        if (thisline_len  > wrap || thisline_len > 380){
            JLLoutput(outputfn,thisline);
                        wordsfoundonline = 0;
            strcpy(thisline, indent);
        }
        return wordsfoundonline;*/
    }else{
        strcat(thisline, nextword);
        strcat(thisline," ");
        return wordsfoundonline+1;
    }
}

int JLLgetnextword(char *nextword, char *readpos){
    char *nwstart;
    nwstart = nextword;
    if (*readpos == 0)
        return 0;
        while(*readpos == ' ' || *readpos == '\t')
            readpos++;
    if (*readpos == '\n' || *readpos == '\r' || *readpos == 0)
        return 0;
    while(*readpos != ' ' && *readpos != '\t' && *readpos != '\n'
                          && *readpos != '\r' && *readpos != 0   ){
        *nextword = *readpos;
        nextword++;
        readpos++;
                if (nextword-nwstart >196) break;
    }
        *nextword = 0;
    return strlen(nwstart);
}

char *JLLfindbeginningofline(char *readpos){
    if (*readpos == 0)
        return readpos;
    while (*readpos == ' ' || *readpos == '\t')
        readpos++;
    if (*readpos == 0)
        return readpos;
    if (*readpos == '\n' || *readpos == '\r')
        readpos++;
    if (*readpos == '\n' || *readpos == '\r')
        readpos++;
    if (*readpos == 0)
        return readpos;
        return readpos;
}

        

int JLLmovereadposontonextword(char *readpos){
    int len = 0;
    if (*(readpos+len) == 0)
        return len;
        while(*(readpos+len) == ' ' || *(readpos+len) == '\t')
            len++;
    if (*(readpos+len) == '\n' || *(readpos+len) == '\r' || *(readpos+len) == 0)
        return len;
    while(*(readpos+len) != ' ' && *(readpos+len) != '\t' && *(readpos+len) != '\n'
                          && *(readpos+len) != '\r' && *(readpos+len) != 0   ){
        len++;
    }
        if (len >= 198) return 197;
    return len;
}

int JLLgetlenofnextline(char *readpos){
    int len=0;
    while (*readpos != '\r' && *readpos != '\n' && *readpos != 0)
          {readpos++;len++;}
    return len;
}

void JLLformat_wrap_output(void (*outputfn)(char *), char *readpos, int wrap){
    char nextword[200];
        char indent[200];
    char thisline[800];

    int indentlen=0;
    int oldindentlen;
    int wordlen;
    int wordsfoundonline=0;
    int addon;
    int doneline;
        
    if (wrap > 370) wrap = 370;
        if (wrap < 5) wrap = 5;

    oldindentlen = indentlen;
    indentlen = JLLgetindentonline(indent, readpos);
    readpos += indentlen;
    strcpy(thisline,indent);
    for(;;){
        wordlen = JLLgetnextword(nextword, readpos);
        addon = JLLmovereadposontonextword(readpos);
                readpos += addon;
        if (wordlen != 0)
        {   wordsfoundonline = JLLprintword(readpos, indent, thisline, nextword, wrap, wordsfoundonline,outputfn);
                }else{
            readpos = JLLfindbeginningofline(readpos);

            oldindentlen = indentlen;
            indentlen = JLLgetindentonline(indent, readpos);
                readpos += indentlen;

            if (*readpos == 0){
                                JLLoutput(outputfn,thisline);
                    return;
            }else if (oldindentlen != indentlen ){
                JLLoutput(outputfn, thisline);
                    strcpy(thisline,indent);
                }
                        else if (JLLgetlenofnextline(readpos) == 0 || wordsfoundonline == 0){
                        JLLoutput(outputfn,thisline);
                                strcpy(thisline,indent);
                }
            wordsfoundonline = 0;
                }
    }
}

void JLLnntp_write_s(char *s){
    nntp_write_s(JLLchan,s,strlen(s));
    nntp_write_s(JLLchan,"\n",1);
}
void JLLcomment_write_s(char *s){
    printf("> %s\n",s);
}

void JLLtext_encode(char *s){
        int noencode=FALSE;
        static char bf[2410];
        int i;
        char *out=bf;
        for (i=0; i<2400 && *s!=0;i++,s++) {
                if (noencode) {
                        if (*s==27) {
                                if (strncmp(s+1,"(B",2)==0) noencode = FALSE;
                        }
                        *out++ = *s;
                        continue;
                }
                if (*s<0) {
                        *out++ = *s++;
                        *out++ = *s;
                } else if (*s=='<') { strcpy(out,"&lt;"); out += strlen(out); }
                else if (*s=='>') { strcpy(out,"&gt;"); out += strlen(out); }
                else if (*s=='&') { strcpy(out,"&amp;"); out += strlen(out); }
                else if (*s=='\r' || *s=='\n') { *s = 0;}
                else if (*s==27) {
                        if (strncmp(s+1,"$B",2)==0) noencode = TRUE;
                        *out++ = *s;
                }
                else *out++ = *s;
        }
        *out++ = 0;
    printf("%s\n",bf);
}



void do_wrap(char *msg)
{
        int len;
        int wrap;
        char *s;

        wrap = atoi(ini_get(I_WRAP_POST));
        dmsg("wrap at %d\n",wrap);
        if (wrap==0) return;
        wrap += 2;
        for (len=0,s=msg; (*s!=0); len++,s++) {
/*              if ((s[0]=='\r') && (s[1]=='\n')) {
                        s[0] = ' ';
                }
                if ((s[0]=='\r') && (s[1]!='\n')) {
                        s[0] = '\n';
                }
*/
                if (len>wrap) if (xisspace(*s)) {
                        *s = '\n';
                        len = 0;
                }
                if ((*s=='\r') || (*s=='\n')) len = 0;
        }
}
char *fix_email(char *s)
{
        static char bf[BFSZ];
        static char bf2[BFSZ];
        char *orig=s;
        ncpy(bf,s,200);
        s = strtok(s,"<> \t\n");
        for (;s!=NULL;) {
                if (strchr(s,'@')!=NULL) {
                        sprintf(bf2,"<%s>",s);
                        return bf2;
                }
                s = strtok(NULL,"<> \t\n");
        }
        return orig;
}
char *eoltospace(char *s)
{
        static char bf[4000];
        ncpy(bf,s,3000);
        for (s=bf;*s!=0;s++) {
                if (*s=='\n') *s = ' ';
                if (*s=='\r') *s = ' ';
        }
        return bf;
}
char *stripeol(char *s)
{
        char *orig=s;

        for (;*s!=0;s++) {
                if (*s=='\r') *s = 0;
                if (*s=='\n') *s = 0;
        }
        return orig;
}
char *real_from(char *xin)
{
        static char bf[BFSZ];
        char *s = udom;

	if (ini_true(I_FROM_REMOTE_USER)) {
		ncpy(bf,mygetenv("REMOTE_USER"),BFSZ-1);
		return bf;
	}
        if (strlen(ini_get(I_POST_DOMAIN))>0) s = ini_get(I_POST_DOMAIN);
        /* if the username already has a domain don't append the login ip */
        if (strchr(guser,'@')==NULL)
		sprintf(bf,"<%s@%s>",guser,s);
	else
        	sprintf(bf,"%.500s",guser);
        if (strlen(guser)==0) return xin;
        return bf;      
}
int islogin(void)
{
        int tout;
        user_read(utag);
	if (ini_true(I_LOGIN_UTAG)) return TRUE; 
        if (ini_true(I_IGNORE_ADDRESS)) {
		if (strlen(ukey)>0) 
		  if (strcmp(user_get("ukey"),ukey)==0) 
		    goto xxx;
		if (ini_true(I_WEB_LOGIN)) {
			r_login(TRUE);
			return TRUE;
		}
		zmsg("User login failed, ukey invalid, please login again (%s) ",ukey);			
		imsg("ukey invalid, please login again (%s) != (%s) \n",user_get("ukey"),ukey);			
                return FALSE;
	}
	if (ini_true(I_WEB_LOGIN)) {
		r_login(TRUE);
		return TRUE;
	}

        if (strcmp(user_get("remote_addr"),mygetenv("REMOTE_ADDR"))==0) {
xxx:            tout = atoi(ini_get(I_LOGIN_TIMEOUT));
                if (tout>0) {
                        if (atoi(user_get("login_time"))+tout*60<lib_gmtime()) {
                                zmsg("User login timed out %d < %d",atoi(user_get("login_time"))+tout*60,lib_gmtime());
                                return FALSE;
                        }
                }

                return TRUE;    
        } else {
		if (strlen(user_get("remote_addr"))==0) {
			imsg("User not currently logged in\n");
		} else {
	                zmsg("User not connecting from correct ip address prev=(%s) != cur=(%s) \n",user_get("remote_addr"),mygetenv("REMOTE_ADDR"));
		}
        }
        return FALSE;
}
void do_login(char *bf)
{
        var_set("login_error",bf);
        set_id();
        do_content();
        tpl_show("login.tpl");
}
void do_addbr(char *msg, char *out);
void r_post(void)  /* from=nnn   max=nnn*/
{
        char uinfo[BFSZ];
        char ruser[BFSZ];
        char xxfrom[BFSZ],xxreply[BFSZ];
        char bf[BFSZ];
        char *xout;
        char *s;
        char attach[BFSZ];
        int ismime=FALSE;
        char xsubj[BFSZ];
        char xfile[BFSZ];
        FILE *f;
        FILE *fout;
        char boundary[BFSZ];
        char newsgroups[BFSZ];
        char xfrom[BFSZ],xname[BFSZ];
        int lp;
        int addmid = FALSE;
        int sk = chan;

        user_read(utag);
        imsg("User data read\n");
        if (ini_true(I_POST_REQUIRE_LOGIN)) {
                if (!islogin()) {
                        imsg("Sorry user isn't logged in\n");
                        sprintf(bf,"Sorry, you must login before posts can be accepted");
                        var_set("login_error",bf);
                        set_id();
                        tpl_show("login.tpl");
                        return;
                }
        }

        imsg("Length of attach field %d\n",strlen(attach));
        ncpy(attach,form_find("attach"),200);
        if (strlen(attach)>0) {
                if (lib_length_file(attach)>3) {
                        imsg("attach file (%s) %d bytes\n",attach,lib_length_file(attach));
                        ismime = TRUE;
                }
        }


        
        if (strcmp("true",ini_get(I_ADD_MID))==0) addmid=TRUE;
        imsg("mid %d, (%s) \n",addmid,ini_get(I_ADD_MID));

        ncpy(ruser,mygetenv("REMOTE_ADDR"),BFSZ-1);

        if (strlen(ini_get(I_POST_USERS))>0) if (!group_match(ini_get(I_POST_USERS),ruser)) {
                printf("Sorry, you (%s) have no permission to post.\n<br>",ruser);
                return;
        }
        
        tpl_init();
        imsg("mid2 \n");
	if (!ini_true(I_FROM_OPTIONAL)) if (!ini_true(I_FROM_REMOTE_USER)) {
         if (strlen(form_find("from"))==0) {
nofrom:         var_set("missing","from");
                tpl_show("required.tpl");
                return;
         }
	}
        if (strlen(form_find("subject"))==0) {
                var_set("missing","subject");
                tpl_show("required.tpl");
                return;
        }

        imsg("mid3 \n");
        ncpy(bf,form_find("required"),400);
        s = strtok(bf,",");
        for (;s!=NULL;) {
                if (strlen(form_find(s))==0) {
                        var_set("missing",s);
                        tpl_show("required.tpl");
                        return;
                }
                var_set(s,form_find(s));
                s = strtok(NULL,",");
        }
        ncpy(bf,form_find("optional"),400);
        s = strtok(bf,",");
        for (;s!=NULL;) {
                if (strlen(form_find(s))!=0) {
                        var_set(s,form_find(s));
                }
                s = strtok(NULL,",");
        }

        imsg("mid5 \n");

        ncpy(group,form_find("group"),BFSZ-1);
        stripeol(group);
        if (strlen(ini_get(I_POST_GROUPS))>0) if (!group_match(ini_get(I_POST_GROUPS),group)) {
                printf("Sorry, posting is not permitted to (%s) \n<br>",group);
                return;
        }

        if (!open_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}
        sprintf(bf,"group %s\015\012",group); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        sprintf(bf,"post\015\012"); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("Post status bad %s\n",nntp_status); return;}

        imsg("From %s\n",form_find("from"));   
        ncpy(xfrom,form_find("from"),200);
        ncpy(xname,form_find("from_name"),200);


	if (ini_true(I_FROM_ALLOW_EMAIL)) {
		ncpy(xname,mygetenv("REMOTE_USER"),BFSZ-1);
	}

	if (ini_true(I_FROM_REMOTE_USER)) {
		ncpy(xxfrom,mygetenv("REMOTE_USER"),BFSZ-1);
		ncpy(xxreply,mygetenv("REMOTE_USER"),BFSZ-1);
	} else {
	        stripeol(xfrom);
	        stripeol(xname);
	        ncpy(xxfrom,real_from(xfrom),400);
	        ncpy(xxreply,fix_email(xfrom),400);
	        if (strlen(xname)>0) {
	                sprintf(xxfrom,"\"%s\" %s",xname,fix_email(real_from(xfrom)));
	                sprintf(xxreply,"\"%s\" %s",xname,fix_email(xfrom));
	        }
		if (!ini_true(I_FROM_NOCHECK)) if (strchr(xxreply,'.')==NULL) {
			zmsg("Sorry, invalid email address given in FROM field\n");
	                return;
		}
	}
	if (!ini_true(I_FROM_ALLOW_EMAIL)) {
	if (ini_true(I_FROM_WEB_LOGIN)) {
		sprintf(xxfrom,"<%s@%s>",mygetenv("REMOTE_USER"),ini_get(I_POST_DOMAIN));
		var_set("from",bf);
		ncpy(xxreply,xxfrom,BFSZ-1);
	}
	} 

        sprintf(bf,"From: %s\015\012",xxreply);      nntp_write_s(chan,bf,strlen(bf)); 
        sprintf(bf,"Sender: %s\015\012",xxfrom);      nntp_write_s(chan,bf,strlen(bf)); 
        sprintf(bf,"Reply-To: %s\015\012",xxreply);      nntp_write_s(chan,bf,strlen(bf)); 
        
        ncpy(xsubj,stripeol(form_find("subject")),BFSZ-1);
        ncpy(bf,xsubj,400);
        strlwr(bf);
        s = strtok(bf," \t"); if (s==NULL) s = bf;
        if (strncmp(s,"cmsg",3)==0)  {
                ncpy(bf,stripeol(form_find("subject")),BFSZ-10);
                strcpy(xsubj,"x-");
                strcat(xsubj,bf);
        }
        sprintf(bf,"Subject: %s\015\012",xsubj);   nntp_write_s(chan,bf,strlen(bf)); 
        ncpy(newsgroups,form_find("newsgroups"),BFSZ-1);
        stripeol(newsgroups);
        if (strlen(newsgroups)>0) {
                sprintf(bf,"Newsgroups: %s\015\012",newsgroups);     nntp_write_s(chan,bf,strlen(bf)); 
        } else {
                sprintf(bf,"Newsgroups: %s\015\012",stripeol(form_find("group")));     nntp_write_s(chan,bf,strlen(bf)); 
        }
        if (addmid) {
                sprintf(bf,"Message-ID: <%d@%s>\015\012",time(NULL),ini_get(I_NEWSHOST));     nntp_write_s(chan,bf,strlen(bf)); 
        }

        ncpy(uinfo,mygetenv("REMOTE_ADDR"),BFSZ-1); strcat(uinfo," ");
        strcat(uinfo,mygetenv("REMOTE_HOST")); strcat(uinfo," ");
        strcat(uinfo,mygetenv("REMOTE_IDENT")); strcat(uinfo," ");
        strcat(uinfo,mygetenv("REMOTE_USER")); strcat(uinfo," ");
        strcat(uinfo,utag); strcat(uinfo," ");
        sprintf(bf,"X-User-Info: %s\015\012",uinfo);     nntp_write_s(chan,bf,strlen(bf)); 
        if (strlen(form_find("ref"))>0) {
                sprintf(bf,"References: %s\015\012",stripeol(form_find("ref")));     nntp_write_s(chan,bf,strlen(bf)); 
        }
        sprintf(boundary,"-=_%s%x",nntp_hostname(),time(NULL));
        if (ismime) {
                tcp_printf(sk,"MIME-Version: 1.0");
                tcp_printf(sk,"Content-Type: multipart/mixed;\r\n\tboundary=\"%s\"",boundary);
                tcp_printf(sk,"");
                tcp_printf(sk,"This is a multi-part message in MIME format.");
                tcp_printf(sk,"");
                tcp_printf(sk,"--%s",boundary);
                tcp_printf(sk,"Content-Type: text/plain");
                tcp_printf(sk,"Content-Transfer-Encoding: 7bit");
        }
        tcp_printf(sk,"");
        
        
        sprintf(bf,"\015\012");       nntp_write_s(chan,bf,strlen(bf)); 

        imsg("Message \n");   
        s = form_find("message");
        imsg("message length %d\n",strlen(s));
        /*s = fix_crlf(s);*/
        
        
        JLLchan = chan;
        if (s!=NULL) 
                if (*ini_get(I_KEEP_FORMATING) == 't')
                        JLLformat_wrap_output(JLLnntp_write_s,s,atoi(ini_get(I_WRAP_POST)));
                else
                {
                        do_wrap(s);
                        imsg("message warpeed (%d)\n",strlen(s));
                        strcpy(xfile,form_find("template"));
                        if (strlen(xfile)>0) {
                                var_set("message",s);
                                s = post_template(xfile);
                        }
                        imsg("message send (%d)\n",strlen(s));
                        if (s!=NULL) nntp_write_s(chan,s,strlen(s));
                }


        if (ismime) {
                tcp_printf(sk,"\r\n--%s",boundary);
                tcp_printf(sk,"Content-Type: %s; name=\"%s\"",attach_type(),attach_showname());
                tcp_printf(sk,"Content-Transfer-Encoding: base64");
                tcp_printf(sk,"Content-Disposition: attachment; filename=\"%s\"",attach_justname());

                tcp_printf(sk,"");
                f = fopen(attach_fname(),"rb");
                if (f==NULL) {zmsg("temp attach file problem %s %s\n",attach_fname(),strerror(errno)); goto failed;}
                fout = fopen(temp_fname(),"w");
                if (fout==NULL) {zmsg("temp file problem %s %s\n",temp_fname(),strerror(errno)); goto failed;}
                base64_encode(f,fout);

                f = fopen(temp_fname(),"r");
                if (f==NULL) {  goto fail2; }
                for (;!feof(f);) {
                        if (fgets(bf,BFSZ-10,f)==NULL) break;
                        s = strchr(bf,'\n');
                        if (s!=NULL) *s = 0;
                        tcp_printf(sk,"%s",bf);
                }
                fclose(f);
fail2:          remove(temp_fname());
                remove(attach_fname());
        }       

        s = cr_decode(user_get("sig"));
        if (strlen(s)>0) {
                if (ismime) {
                        tcp_printf(sk,"\r\n--%s",boundary);
                        tcp_printf(sk,"Content-Type: text/plain");
                        tcp_printf(sk,"Content-Transfer-Encoding: 7bit");
                }
                tcp_printf(sk,"");
                nntp_write_s(chan,s,strlen(s));
        }

        if (ismime) {
                tcp_printf(sk,"\r\n--%s--",boundary);
        }
                
        sprintf(bf,"\015\012.\015\012");       nntp_write_s(chan,bf,strlen(bf)); 
        for (lp=0;nntp_isbusy(chan) && lp<10000;lp++) {
                nntp_write_now(chan);
        }


        imsg("readstatus (%d)\n",strlen(s));
        read_status(); /* Wait for the channel to close */
        imsg("readstatxxxus (%d)\n",strlen(s));

        
        var_set("post_status",nntp_status);
        if (atoi(nntp_status)==240) {
                var_set("ok","TRUE");
        }
        tpl_show("posted.tpl");
        sprintf(bf,"quit\015\012"); nntp_write_s(chan,bf,strlen(bf)); 
        read_status(); /* Wait for the channel to close */
        return;
failed:
        zmsg("Unable to read attachment file");
        return;
} 
char *temp_fname(void)
{
        static char fname[BFSZ];
        char *s;
        static char bf[BFSZ];
        if (strlen(fname)!=0) return fname;
        strcpy(fname,ini_work("teXXXXXX"));
        s = mktemp(fname);
        if (s==NULL) s = "attach2.tmp";
        ncpy(bf,s,BFSZ-1);
        strcpy(fname,bf);
        return fname;
}

void r_logout(void)
{
        int g;

	printf("Set-Cookie: dnews_utoken=%s; expires=%s\n","",cookie_date_plus(60*60*12));
	imsg("Logout. Set-Cookie: dnews_utoken=%s; expires=%s\n","",cookie_date_plus(60*60*12));
        done_content = TRUE;
	printf("Content-type: %s\n\n",content_type());
        
	user_read(utag);
        user_set("remote_addr","");

        for (g=0; g<ngroups; g++) {
                groups[g].lasttime = 1;
        }

        user_write(utag);
        f_login();
}
void r_catchup(void)
{
        int g;
        user_read(utag);

        for (g=0; g<ngroups; g++) {
                groups[g].lasttime = 2;
        }

        user_write(utag);
        r_user();
}
void show_dline(char *s)
{
        char bf[BFSZ];
        char gname[BFSZ];
        char mod[BFSZ];
        char from[BFSZ];
        char to[BFSZ];
        char items[BFSZ];

        ncpy(bf,s,BFSZ-1);
        s = strtok(bf," "); if (s==NULL) return;
        ncpy(gname,s,BFSZ-1);
        s = strtok(NULL," "); if (s==NULL) return;
        ncpy(to,s,BFSZ-1);
        s = strtok(NULL," "); if (s==NULL) goto doit;
        ncpy(from,s,BFSZ-1);
        s = strtok(NULL," "); if (s==NULL) goto doit;
        strcpy(mod,"");
        if (*s=='m') strcpy(mod,"(Moderated)");
        s = strtok(NULL," "); if (s==NULL) goto doit;
        ncpy(items,s,BFSZ-1);
doit:;
        if (gname[0]=='+') {
                strcat(to,".");
                if (group_match(ini_get(I_ALLOW),to)) {
                        printf("<li><a href=\"%s?cmd=listall&group=%s&utag=%s\">%s.. %s groups</a> <br>",path_script,towww(to),utage,to,from);
                }
        } else {
                if (group_match(ini_get(I_ALLOW),gname)) {
                        printf("<li><a href=\"%s?cmd=xover&group=%s&utag=%s\">%s, %s items %s</a> <br>",path_script,towww(gname),utage,gname,items,mod,utage);
                }
        }
}

static char topname[BFSZ];
void r_list(void)
{
	imsg("r_list\n");
        tpl_init();
	imsg("r_list2\n");

        if (ini_true(I_REQUIRE_LOGIN) || ini_true(I_WEB_LOGIN)) {
                if (!islogin()) {
                        f_login();
                } else {
                        r_user();
                }
                return;
        }
	imsg("r_list3\n");
        if (!open_status()) {zmsg("Could not read opening message - %s",nntp_status); return;}

	imsg("r_list4\n");

        tpl_show(topname);
	imsg("r_list5\n");
        dmsg("top done\n");
}
/* ---------------------------------------- xxx.ini file processing -- */
void db_setscript(char *script)
{
        char *last;
        char *s;
        char bf[BFSZ];
        ncpy(path_script,script,BFSZ-1);
        ncpy(bf,script,BFSZ-1);
        last = bf-1;
        for (s=bf;*s!=0;s++) {
                if (*s=='/') last = s;
                if (*s=='\\') last = s;
        }
        ncpy(rootname,last+1,BFSZ-1);
        s = strchr(rootname,'.');
        if (s!=NULL) *s = 0;
        if (strlen(rootname)==0) strcpy(rootname,"dnewsweb");
}


char *ini_values[200];
int ini_find(char *s)
{
        int i;
        for (i=0; ini_names[i]!=NULL; i++) {
                if (strcmp(ini_names[i],s)==0) return i;
        }
        return -1;
}
char *ini_get(int x)
{
        if (ini_values[x]!=NULL) return ini_values[x];
        return "";
}
int ini_read(char *epath)
{
        char bf[BFSZ];
        char bf2[BFSZ];
        char bf3[BFSZ];
        char xroot[BFSZ];
        char xin[5000];
        char *last;
        FILE *f;
	int k;
        int i;
        char *s;

        db_setscript(mygetenv("SCRIPT_NAME"));
        sprintf(bf,"%s.ini",rootname);
        f = fopen(bf,"r");
        strcpy(bf3,bf);
        if (f==NULL) {
                imsg("ini file not in working dir, searching in path {%s} \n",epath);
                strcpy(xroot,epath);
                last = xroot;
                for (s=xroot; *s!=0; s++) {
                        if (*s=='/') last = s;
                        if (*s=='\\') last = s;
                }
                *last = 0;
                sprintf(bf,"%s/%s.ini",xroot,rootname);
                imsg("Looking in (%s) for ini file\n",bf);
                f = fopen(bf,"r");
                strcpy(bf2,bf);
        }
        if (f==NULL) {
                sprintf(bf,"/etc/%s.ini",rootname);
                imsg("Last resort, looking in (%s) for ini file\n",bf);
                f = fopen(bf,"r");
        }
        if (f==NULL) {
                done_content = TRUE;
                if (docache) printf("Pragma: cache\n");
                printf("Content-type: %s\n\n",content_type());
                done_content = TRUE;
                emsg("Unable to find ini file in <br> {%s} \n",bf3);
                emsg("Also looked in {%s} <br> and {%s} <br>\n",bf2,bf);
#ifdef WIN32
                GetCurrentDirectory(200,bf);
                emsg("Place dnewsweb.ini file in this directory {%s} \n",bf);
#endif
                return FALSE;
        }       
        for (;!feof(f);) {
          if (fgets(xin,4000,f)!=NULL) {
                ncpy(bf,xin,BFSZ-20);
                s = strtok(bf," \t\n"); if (s==NULL) continue;
                if (*s==0 || *s=='#') continue;
                i = ini_find(s);
                if (i<0) { 
                        do_content();
                        emsg("Unknown ini file setting {%s} \n",s); continue; 
                }
                s = strtok(NULL,"\n"); if (s==NULL) continue;
		for (k=strlen(s)-1; k>=0; k--) {
			if ((s[k]!=' ') && (s[k]!='\t')) {
				s[k+1] = 0;
				break;
			}
		}
                ini_values[i] = strdup(s);
          }
        } 
        fclose(f);      
        return TRUE;
}
 
/* ---------------------- Missing bits that are needed ---------------------- */
#define OUTSIZE 5000
static char output[OUTSIZE];
void emsg_do(int x, char *s);
int emsg(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsprintf(output, format, arg_ptr);
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, EMSG ERROR TOO LONG\n");
        emsg_do(D_ERROR,output);
        return TRUE;
}
int filemsg(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsprintf(output, format, arg_ptr);
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, EMSG ERROR TOO LONG\n");
        emsg_do(D_ERROR,output);
        return TRUE;
}
int imsg(const char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;
        if (!dodebug) return 0;
        va_start(arg_ptr, arg_list);
        format = (char *) arg_list;
        len = vsprintf(output, format, arg_ptr);
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, EMSG ERROR TOO LONG\n");
        emsg_do(D_INFO,output);
        return TRUE;
}
void h_printf(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsprintf(output, format, arg_ptr);
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, EMSG ERROR TOO LONG\n");
        printf("%s",output);
        emsg_do(D_DEBUG,output);
}
void zmsg(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsprintf(output, format, arg_ptr);
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, EMSG ERROR TOO LONG\n");
/*      if (!done_content) {
                if (docache) printf("Pragma: cache\n");
                printf("Content-type: %s\n\n",content_type());
                done_content = TRUE;
        }
        */
        if (strlen(output) + strlen(etext)<10000) {
                strcat(etext,output);
        }
/*      printf("%s",output);*/
        emsg_do(D_INFO,output);
}
int wmsg(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsprintf(output, format, arg_ptr);
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, EMSG ERROR TOO LONG\n");
        emsg_do(D_INFO,output);
        return TRUE;
}
static int domoredebug=FALSE;
int dmsg(char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        int len;
        if (!dodebug) return 0;
        if (!domoredebug) return 0;
        va_start(arg_ptr, arg_list);
        format = arg_list;
        len = vsprintf(output, format, arg_ptr);
        if (len>=OUTSIZE) emsg_do(D_ERROR,"FATAL, EMSG ERROR TOO LONG\n");
        if (domoredebug) emsg_do(D_DEBUG,output);
        return TRUE;
}
void emsg_reset(void)
{
        remove(log_file);
}
void emsg_do(int x, char *s)
{
        time_t ltime;
        char bf[BFSZ];
        FILE *f;
        time( &ltime );
        strcpy(bf,ctime(&ltime));
        bf[19] = 0;

        if (x==D_ERROR)  {
                do_content();
                printf("<br> Error: %s <br>",s);
        }
        f = fopen(log_file,"a");
        if (f==NULL) {perror(log_file); return; }
        fprintf(f,"%s, %s",bf+4,s);
        fclose(f);              
}
/* ---------------------- Missing bits that are needed ---------------------- */
char *group_name(int i)
{
        return "(none)";
}
#ifndef unix
int lib_mail_file(char *to, char *subj, char *fname)
{
        return TRUE;
}
int lib_freespace(char *s)
{
        return 100000;
}
#endif
int diskuse_get(void)
{
        return 0;
}
char *nt_pcname(void);

char *lib_findfile(char *x)
{
        return NULL;
}
void dnews_manager_report(char *s)
{
        
}
int post_local(String *xitem, char *addr, int ismod)
{
        return TRUE;
}
void dnews_exit(char *reason, char *file, int line)
{
        printf("Crashing\n");
        exit(1);
}



#ifdef WIN32
char *nt_pcname(void)
{
        return "pcname";
}
#endif
/* ------------------ library of stuff for web --------------------*/

static char *query_name[1000];
static char *query_val[1000];
static int nquery;
/* Query string */
char *lib_encode(char *s)
{
   char *ss=s;
  for (;*s!=0;s++) {
    if (xisspace(*s)) *s = '+';
  }
  return ss;
}
char *lib_encode_more(char *bf,char *s)
{
        char *out=bf;
	int i;
        if (s==NULL) return "";
	if (strlen(s)>600) return s;

        for (i=0; i<1000 && *s!=0;i++,s++) {
                if (*s=='&') { strcpy(out,"%26"); out += strlen(out); }
                else if (*s=='#') { strcpy(out,"%23"); out += strlen(out); }
                else if (*s==' ') { strcpy(out,"+"); out += strlen(out); }
                else if (*s=='+') { strcpy(out,"%2b"); out += strlen(out); }
                else if (*s=='|') { strcpy(out,"%7c"); out += strlen(out); }
                else if (*s=='%') { strcpy(out,"%25"); out += strlen(out); }
                else *out++ = *s;
        }
        *out++ = 0;
        return bf;
}
char *value_encode(char *s)
{
        static char bf[18010];
        int noencode=FALSE;
        int i;
        int iniso;
        int addend=FALSE;
        char *out=bf;

        if (s==NULL) return "";
        for (i=0; i<2000 && *s!=0;i++,s++) {
                if (noencode) {
                        if (*s==27) {
                                if (strncmp(s+1,"(B",2)==0) noencode = FALSE;
                        }
                        *out++ = *s;
                        continue;
                }
                if (*s=='<') { strcpy(out,"&lt;"); out += strlen(out); }
                else if (*s=='>') { strcpy(out,"&gt;"); out += strlen(out); }
                else if (*s=='&') { strcpy(out,"&amp;"); out += strlen(out); }
                else if (*s=='"') { strcpy(out,"&#34;"); out += strlen(out); }
                else if (*s==27) {
                        if (strncmp(s+1,"$B",2)==0) noencode = TRUE;
                        *out++ = *s;
                } 
                else *out++ = *s;
        }
        *out++ = 0;
        return bf;
}
char *head_decode(char *s)
{
        return s;

        /*
        static char bf[10000];
        char *out,*s2;
        int iniso=FALSE;

        for (out=bf;*s!=0;s++) {
                if ((strncmp(s,"=?iso",5)==0) || (strncmpnc(s,"=?ISO",5)==0)) {
                        s2 = strchr(s+3,'?');
                        if (s2!=NULL) s = s2;
                        iniso = TRUE;
                        strcpy(out,"\033$B"); out+= strlen(out);
                        continue;
                }               
                if (iniso) if ((strncmp(s,"?=",2)==0)) {
                        s = s+1;
                        iniso = FALSE;
                        strcpy(out,"\033(B"); out+= strlen(out);
                        continue;
                }
                *out++ = *s;
        }
        *out++ = 0;
        return bf;
        */
}
/*
Same as value encode except.
user@a.b.c  --> <a href="mailto:user@a.b.c"> user@a.b.c </a>
http://netwin.co.nz  --> <a href="http://netwin.co.nz"> htp://netwin.co.nz</a>


*/
char *ref_encode_url(char *protocol, char *instr);
char *ref_encode_mail(char *instr);
char *ref_encode(char *s)
{
        static char bf[5000];
        strcpy(bf,s);
        if (strchr(s,27)!=NULL) return bf;
        s = ref_encode_mail(bf);
        s = ref_encode_url("http:",s);
		s = ref_encode_url("https:",s);
		s = ref_encode_url("ftp:",s);
		s = ref_encode_url("telnet:",s);
        return s;
}
char *ref_encode_mail(char *instr)
{
        char bf[BFSZ];
        char bf2[BFSZ];
        char *s,*s1,*s2;
        s = instr;
again:
        s = strchr(s,'@');
        if (s==NULL) return instr;
        if (s>instr) if (s[-1]<0) {
                s++;
                goto again;
        }
        for (s1=s;s1>instr;s1--) {
                if (xisspace(*s1)) {
                        s1++;
                        break;
                }
        }
        for (s2=s;*s2!=0;s2++) {
                if (xisspace(*s2)) break;
        }
        s2--;
        ncpy(bf,s1,s2-s1+1);
	if (strstr(bf,"http")!=NULL) {
                s++;
                goto again;
	}
        sprintf(bf2,"<a href=\"mailto:%s\">%s</a>",bf,bf);
        memmove(s1+strlen(bf2),s2+1,strlen(s2+1)+1);
        strncpy(s1,bf2,strlen(bf2));
        s = s1 + strlen(bf2);
        goto again;
} 
char *ref_encode_url(char *protocol,char *instr)
{
        char *s,*s1,*s2;
        char bf[BFSZ];
        char bf2[BFSZ];
        s = instr;
again:
		s = strstr(s,protocol);
        if (s==NULL) return instr;
        if (s>instr) if (s[-1]<0) {
                s++;
                goto again;
        }
        s1 = s;
        for (s2=s;*s2!=0;s2++) {
                if (xisspace(*s2)) break;
        }
        s2--;
        ncpy(bf,s1,s2-s1+1);
        sprintf(bf2,"<a%s%s href=\"%s\">%s</a>",(strlen(ini_get(I_LINK_ADD))>0)?" ":"",ini_get(I_LINK_ADD),bf,bf);
        memmove(s1+strlen(bf2),s2+1,strlen(s2+1)+1);
        strncpy(s1,bf2,strlen(bf2));
        s = s1 + strlen(bf2);
        goto again;
} 
char *decode_base64s(char *s);
char *decode_base64s(char *s)
{
        static char bf[2000];
        int n = decode_base64(s,bf);
        bf[n] = 0;
        return bf;
}
char *decode_base64text(char *s) {
        static char bf[2000];
                char *c,*d;
                int n = decode_base64(s,bf);
                bf[n] = 0;
                /* cleverly go thru and turn \r\n into just \n for decoded text messages so
                that messages encoded with both don't stuff up the formatting when we display
                the text */
                for(c=d=bf;*c!=0;c++,d++) {
                        if (((c[0]=='\r')||(c[0]=='\n'))&&((c[1]=='\r')||(c[1]=='\n'))) {c++; *d='\n';}
                        else *d=(*c=='\r')?'\n':*c; 
                };
                *d=0;
        return bf;
};
/* quoted printable decoder - stolen from ralph, but it seems to work :-) */
char hexbyte(char *s)
{
        char bf[3];
        int x;
        strncpy(bf,s,2);
        bf[2] = 0;
        sscanf(bf,"%x",&x);
        return (char) x;
}

static char qeol[2]="\n";
char *decode_quote_eol(void){
        return qeol;
}

char *decode_quote(char *s){
 	static char bf[2000];
	int i;
	int truncated=FALSE;
	char *out=bf;
	for (i=0; i<2000 && *s!=0;i++,s++) {
		if (*s<0) {
			*out++ = *s++;
			*out++ = *s;
		} else if (*s=='=') {
			if (s[1]==0) { truncated=TRUE; continue;}
			if (s[1]=='\n' || s[1]=='\r') { if (s[2]==0) truncated=TRUE; continue;}
			*out++ = hexbyte(s+1);
			s+=2;
		} else *out++ = *s;
	}
	*out++ = 0;
	if (truncated) qeol[0]=0; else qeol[0]='\n';
	return bf;
}
/* Chris's testing? quoted printable decoder - broken!
char *decode_quote(char *s)
{
        static char bf[2000];
        int i;
        char *out=bf;
        for (i=0; i<2000 && *s!=0;i++,s++) {
                if (*s<0) {
                        *out++ = *s++;
                        *out++ = *s;
                } else if (strncmp(s,"=3D",3)==0) *out++ = '=';
                else if (*s=='=') *out++ = '\n';
                else *out++ = *s;
        }
        *out++ = 0;
        return bf;
}
*/

char *wrap_encode(char *s);
char *text_encode(char *s)
{
        int noencode=FALSE;
        static char bf[2010];
        int i;
        char *out=bf;
        for (i=0; i<2000 && *s!=0;i++,s++) {
                if (noencode) {
                        if (*s==27) {
                                if (strncmp(s+1,"(B",2)==0) noencode = FALSE;
                        }
                        *out++ = *s;
                        continue;
                }
                if (*s<0) {
                        *out++ = *s++;
                        *out++ = *s;
                } else if (*s=='<') { strcpy(out,"&lt;"); out += strlen(out); }
                else if (*s=='>') { strcpy(out,"&gt;"); out += strlen(out); }
                else if (*s=='&') { strcpy(out,"&amp;"); out += strlen(out); }
                else if (*s==27) {
                        if (strncmp(s+1,"$B",2)==0) noencode = TRUE;
                        *out++ = *s;
                }
                else *out++ = *s;
        }
        *out++ = 0;
        return ref_encode(wrap_encode(bf));
}
char *wrap_encode(char *s)
{
        static char bf[4000];
        int i;
        char *out=bf;
        int len;
        int w = atoi(ini_get(I_WRAP_TEXT));
        if (w==0) return s;
        dmsg("Wrap text at %d\n",w);
        len = 0;
        for (i=0; (i<2000) && (*s!=0);i++,s++,len++) {
                if (*s=='\n') len = 0;
                if (*s=='\r') len = 0;
                if ((*s=='\n') || (s[1]==0)) if (ini_true(I_ADD_BR)) {
                        strcpy(out,"<br>"); out+= strlen(out);
                }
                if (len>w) {
                        if (xisspace(*s)) {
                                if (ini_true(I_ADD_BR)) {
                                        strcpy(out,"<br>"); out+= strlen(out);
                                }
                                *out++ = '\n';
                                len = 0;
                                continue;
                        }
                } 
                *out++ = *s;
        }
        *out++ = 0;
        return bf;
}
char *mygetenv(char *v)
{
        char *s;
#ifdef VMS
        char bf[2000];
        sprintf(bf,"WWW_%s",v);
        v = bf;
#endif
        s = getenv(v);
        if (s==NULL) return "";
        return s;
}
char *query_find(char *s)
{
        int i;
        for (i=0; i<nquery; i++) if (strcmp(query_name[i],s)==0) return query_val[i];
        return "";
}

int log_hacker(void)
{
	time_t t;
	FILE *f;
	char *q;
	do_content();
	emsg("Hacker attempted to abuse this system, details being logged\n");
	printf("<html><h3>Fatal error occured, this appears to be a hacking attempt, your details are now being logged for the system administrator, we suggest you contact the adminstrator to explain your actions</h3></html>\n");
	f = fopen(ini_work("hacker.log"),"a");
	if (f==NULL) return TRUE;

        q =  mygetenv("QUERY_STRING");
	
	t = time(NULL);
	fprintf(f,"Possible hacking attempt at %s\n",ctime(&t));
	fprintf(f,"remote_addr %s\n",mygetenv("REMOTE_ADDR"));
	fprintf(f,"remote_host %s\n",mygetenv("REMOTE_HOST"));
	fprintf(f,"remote_ident %s\n",mygetenv("REMOTE_IDENT"));
	fprintf(f,"remote_user %s\n",mygetenv("REMOTE_USER"));
	if (q!=NULL) fprintf(f,"Hackers query string was %s\n",q);
	fprintf(f,"\n\n");
	fclose(f);

	return TRUE;
}
int query_get(void)
{
        char *q;
        char *cl;
        char bf[10000],val[2000],name[BFSZ];
        int x;

        q =  mygetenv("QUERY_STRING");
        if (q==NULL) return FALSE;
        ncpy(bf,q,9000); cl = bf;
        for(x=0;cl[0] != '\0';) {
                getword(val,cl,'&',1999);
                plustospace(val);
                unescape_url(val);
                getword(name,val,'=',BFSZ-1);
		if (strlen(name)>400) continue;
		if (strlen(val)>400) {
			log_hacker();
			exit(0);
			continue;
		}
                query_name[x] = strdup(name);
                query_val[x] = strdup(val);
		x++;
                /*printf("[%d] {%s} = {%s} \n",x,query_name[x],query_val[x]);*/
        }
        nquery = x;
        return TRUE;
}
void getword(char *word, char *line, char stop, int len) 
{
    int x = 0,y;
    len--;

    for(x=0;((line[x]) && (line[x] != stop));x++) {
        word[x] = line[x];
	if (x>=len) break;
    }

    word[x] = '\0';
    if(line[x]) ++x;
    y=0;

    while(line[y++] = line[x++]);
}
char x2c(char *what) 
{
    register char digit;

    digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
    digit *= 16;
    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
    return(digit);
}

void unescape_url(char *url) 
{
    register int x,y;

    for(x=0,y=0;url[y];++x,++y) {
        if((url[x] = url[y]) == '%') {
            url[x] = x2c(&url[y+1]);
            y+=2;
        }
    }
    url[x] = '\0';
}

void plustospace(char *str) 
{
    register int x;

    for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' ';
}


static char *form_name[1000];
static char *form_val[1000];
static int nform;
char *makeword(char *line, char stop) ;
char *fmakeword(FILE *f, char stop, int *cl);
void convert_crlf(char *s); /* turn crlf into lf's */

char *attach_fname(void)
{
        static char fname[BFSZ];
        char *s;
        static char bf[BFSZ];
        if (strlen(fname)!=0) return fname;
        strcpy(fname,ini_work("atXXXXXX"));
        imsg("attach_fname_mask(%s)\n",fname);
        s = mktemp(fname);
        if (s==NULL) s = "attach.tmp";
        imsg("attach_fname_result(%s)\n",s);
        strcpy(bf,s);
        strcpy(fname,bf);
        return fname;
}
static char a_type[BFSZ],a_name[BFSZ];
char *attach_type(void)
{
        return a_type;
}
char *attach_showname(void)
{
        return a_name;
}
char *attach_justname(void)
{
	static char bf[BFSZ];
	char *last;
	char *s;
	static char tmp[BFSZ];
	ncpy(tmp,a_name,200);
	last = NULL;
	for (s=tmp;*s!=0;s++) {
		if (*s=='/') last = s;
		if (*s=='\\') last = s;
	}
	if (last==NULL) return a_name;
	ncpy(bf,last+1,200);
	return bf;

}

#define BODY_LEN 66000
void form_get_mime(char *content)
{       
        char bf[BFSZ];
        char bf2[BFSZ];
        char boundary[BFSZ];
        char bound_part[BFSZ];
        char bound_end[BFSZ];
        int cl;
        char name[BFSZ];
        char fname[BFSZ];
        char body[BODY_LEN];
        char tmp[BFSZ];
        int inhead;
        int i,n;
        char lasteol = FALSE;
        FILE *attach;
        char *s = mygetenv("CONTENT_LENGTH");
        cl = atoi(s);
	strcpy(body,"");
        strcpy(fname,"");
        attach = NULL;
        s = strstr(content,"boundary=");
        if (s==NULL) {
                /*do_content();*/
                imsg("Can't find boundary in mime contents %s",content);
                strcpy(boundary,"none");
                goto xxx;
        }
        s += 9;
        strcpy(boundary,get_quote(s));
        imsg("Got boundary (%s) \n",boundary);
xxx:    sprintf(bound_part,"--%s",boundary);
        sprintf(bound_end,"--%s--",boundary);
#ifdef FIX_STDOUT
        _setmode(_fileno(stdin),_O_BINARY);
#endif
        for (;(!feof(mystdin)) && (cl>0);) {
                n = 0;
                for (i=0; (i<400) && (!feof(mystdin)) && (cl>0); i++) {
                        bf[i] = fgetc(mystdin);
                        cl--;
                        n = i+1;
                        if (bf[i]=='\n') break;
                /*      if ((bf[i]=='\r') && (bf[i]!='\n')) break;*/

                }
                bf[n] = 0;
                if (strncmp(bf,bound_part,strlen(bound_part))==0) {
                        imsg("Found Boundary %s",bf);
                        inhead = TRUE;
                        if (attach!=NULL) {
                                fclose(attach);
                                attach = NULL;
                                sprintf(tmp,"%s\r\n",attach_fname()); 
                                cgi_addvar(name,tmp);
                                strcpy(fname,"");
                        } else cgi_addvar(name,body);
                } else if (strncmp(bf,bound_end,strlen(bound_end))==0) {
                        if (attach!=NULL) {
                                fclose(attach);
                                strcpy(fname,"");
                                attach = NULL;
                                sprintf(tmp,"%s\r\n",attach_fname()); 
                                cgi_addvar(name,tmp);
                                strcpy(fname,"");
                        } else cgi_addvar(name,body);
                        break;
                } else {
                 if (inhead) {
/*      Content-Disposition: form-data; name="reply" */
                        imsg("Mime Headers %s",bf);
                        if (strcmp(bf,"\r\n")==0) inhead = FALSE;
                        if (xisspace(bf[0])) goto skip;
                        strcpy(bf2,bf); strlwr(bf2);
                        if (strstr(bf2,"content-type: ")!=NULL) {
                                s = bf + 14;
                                ncpy(a_type,s,BFSZ-1);
                                s = strchr(a_type,';'); if (s!=NULL) *s = 0;
                                s = strchr(a_type,'\r'); if (s!=NULL) *s = 0;
                                s = strchr(a_type,'\n'); if (s!=NULL) *s = 0;
                        }
                        if (strstr(bf2,"content-disposition:")!=NULL) {
skip:                           s = strstr(bf,"name="); if (s==NULL) continue;
                                strcpy(name,get_quote(s+5));
                                s = strstr(bf,"filename="); if (s==NULL) continue;
                                strcpy(fname,get_quote(s+9));
                                strcpy(a_name,fname);
				if ((attach==NULL)&&(strlen(a_name)>0)) {
                                        attach = fopen(attach_fname(),"wb");
                                        if (attach==NULL) emsg("Cannot create (%s) (%s)\n",attach_fname(),strerror(errno));
                                        imsg("Writing to %s %p\n",attach_fname(),attach);
                                }
                                lasteol = FALSE;
                        }
                        strlwr(bf);

                 } else {
                        if (attach!=NULL) {
                                if (lasteol) fwrite("\r\n",1,2,attach);
                                lasteol = FALSE;
                                if (n>2) if (strncmp(bf+n-2,"\r\n",2)==0) {
                                        n-=2;
                                        lasteol = TRUE;
                                } 

                                fwrite(bf,1,n,attach);
                        } else if (strlen(name)>0) {
                                if (strlen(body)>(BODY_LEN-400)) continue;
                                strcat(body,bf);
                        }
                 }
                }
        }
        if (attach!=NULL) fclose(attach);
        attach = NULL;
        imsg("cl = %d\n",cl);
        
}


void form_get(void)
{
        int x,cl;
        char content[BFSZ];
        char lwr_content[BFSZ];
        char *s = mygetenv("CONTENT_LENGTH");
	if (s==NULL) return;
        cl = atoi(s);

        ncpy(content,mygetenv("CONTENT_TYPE"),BFSZ-1);
        ncpy(lwr_content,content,BFSZ-10);
        imsg("Form content (%s)\n",content);
        strlwr(lwr_content);
        if (strstr(lwr_content,"multipart/form-data")!=NULL) {
                form_get_mime(content);
                return;
        }

        for(x=0;cl && (!feof(mystdin));x++) {
                form_val[x]= fmakeword(mystdin,'&',&cl);
                plustospace(form_val[x]);
                unescape_url(form_val[x]);
                form_name[x] = makeword(form_val[x],'=');
                convert_crlf(form_val[x]);
        }
        nform = x;
}
void convert_crlf(char *s)
{
        char *out=s;
        return ;
        for (;*s!=0;s++) {
                if ((*s == '\r') && (s[1]!='\n')) *s = '\n';
                if (*s == '\r') s++;
                *out++ = *s;
        }
        *out++ = 0;
}
char *makeword(char *line, char stop) 
{
    int x = 0,y;
    char *word = (char *) malloc(sizeof(char) * (strlen(line) + 1));

    for(x=0;((line[x]) && (line[x] != stop));x++)
        word[x] = line[x];

    word[x] = '\0';
    if(line[x]) ++x;
    y=0;

    while(line[y++] = line[x++]);
    return word;
}

char *fmakeword(FILE *f, char stop, int *cl) 
{
    int wsize;
    char *word;
    int ll;

    wsize = 8024;
    ll=0;
    word = (char *) malloc(sizeof(char) * (wsize + 1));

    while(1) {
        word[ll] = (char)fgetc(f);
        if(ll==wsize) {
            word[ll+1] = '\0';
            wsize+=8024;
            word = (char *)realloc(word,sizeof(char)*(wsize+1));
        }
        --(*cl);
        if((word[ll] == stop) || (feof(f)) || (!(*cl))) {
            if(word[ll] != stop) ll++;
            word[ll] = '\0';
            return word;
        }
        ++ll;
    }
}


char *form_find(char *s)
{
        int i;
        for (i=0; i<nform; i++) if (strcmp(form_name[i],s)==0) return form_val[i];
        return "";
}
char *either_find(char *s)
{
        int i;
        for (i=0; i<nform; i++) if (strcmp(form_name[i],s)==0) return form_val[i];
        return query_find(s);
}

char *form_find_i(char *s, int i)
{
        char bf[BFSZ];
        sprintf(bf,"%s%d",s,i); s = bf;
        for (i=0; i<nform; i++) if (strcmp(form_name[i],s)==0) return form_val[i];
        return "";
}

char *email_name(char *email)
{
        static char bf[BFSZ];
        char *s2;
        char *s;
        s = strchr(email,'(');
        if (s!=NULL) {
                ncpy(bf,s+1,BFSZ-1);
                s = strchr(bf,')');
                if (s!=NULL) *s = 0;
        }
        ncpy(bf,email,BFSZ-1);
        s = strchr(bf,'@');
        s2 = strchr(bf,' ');
        if (s==NULL) s = s2;
        if (s2!=NULL) if (s2<s) s = s2;
        if (s!=NULL) *s = 0;
        return bf;
}


int group_match(char *wild, char *grp22)
{
        char bf[10000];
        char grp[BFSZ];
        int m=TRUE,lastm;
        char *s;

        ncpy(grp,grp22,BFSZ-1); strlwr(grp);
        lastm = FALSE;
        ncpy(bf,wild,10000-1);
        s = strtok(bf,",");
        for (;s!=NULL;) {
                m = TRUE;
                if (*s=='!') {
                        s++;
                        m = FALSE;
                }
                if (match_wild(s,grp)) { lastm = m; } 
                s = strtok(NULL,",");
        }
        return lastm;
}


int  show_top(char *type, char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        char output[BFSZ];
        va_start(arg_ptr, arg_list);
        format = arg_list;
        vsprintf(output, format, arg_ptr);

        if (show_headfile(type,output)) return TRUE;
        printf("<html><head><title>%s</title>",output);
        printf("</head><body>"); 
        return FALSE;
}
void show_end(char *type)
{
        show_headfile(type,NULL);
        if (strlen(ini_get(I_NOADVERT))==0) netwin_advert();
        printf("</body>"); 
        printf("</html>"); 
}
int show_headfile(char *type, char *title)
{
        char fname[BFSZ];
        char bf[BFSZ],bf2[BFSZ];
        char *s;
        FILE *f;
        char *ext = ".top";
        if (title==NULL) ext = ".end";
        if (strlen(ini_get(I_HEADERS))==0) return FALSE;
        sprintf(fname,"%s/%s%s",ini_get(I_HEADERS),type,ext);
        dmsg("Top file (%s)",fname);
        f = fopen(fname,"r");
        if (f==NULL) {
                if (title!=NULL) printf("Top or End file missing {%s} <br>\n",fname);   
                return FALSE;
        }
        for (;!feof(f);) {
                if (fgets(bf,BFSZ-10,f)==NULL) break;
                if (title!=NULL) {
                  s = strstr(bf,"$title$");
                  if (s!=NULL) {
                        strcpy(bf2,s+7);
                        strcpy(s,title);
                        strcat(s,bf2);
                  }
                }
                printf("%s",bf);
        }       
        fclose(f);
        return TRUE;
}
char *file_tpl(char *fname)
{
        char bf[BFSZ];
        static char rslt[BFSZ];
        ncpy(bf,tplname,BFSZ-1);
        if (strlen(bf)>0) strcat(bf,"/");

        if (strlen(ini_get(I_TEMPLATES))>0) 
        sprintf(rslt,"%s/%s%s",ini_get(I_TEMPLATES),bf,fname);
        else  sprintf(rslt,"%s/%s%s",ini_get(I_HEADERS),bf,fname);
#ifdef VMS
        sprintf(rslt,"%s%s%s",ini_get(I_TEMPLATES),bf,fname);
#endif
        return rslt;
        
}

int tpl_show_file(char *xfname)
{
        FILE *f;
        char fname[BFSZ];
        char bf[66000];
        
        ncpy(fname,file_tpl(xfname),BFSZ-1);

        f = fopen(fname,"r");
        if (f==NULL) {
                printf("Include file missing {%s} <br>\n",fname);       
                return FALSE;
        }

        for (;!feof(f);) {
                if (fgets(bf,BFSZ-10,f)==NULL) break;
		tpl_replace_vars(bf);
                printf("%s",bf);
        }       
        fclose(f);
        return TRUE;
}


char *towww(char *s)
{
  static char bf[BFSZ],*out;
  for (out=bf;*s!=0;s++) {
        if (xisspace(*s)) *s = '+';
        if (*s=='+') {sprintf(out,"%%%x",*s); out += strlen(out);}
        else if (*s=='&') {sprintf(out,"%%%x",*s); out += strlen(out);}
        else *out++ = *s;
  }
  *out++ = 0;
  return bf;
}
char *post_template(char *xfname)
{
        FILE *f;
        char fname[BFSZ];
        char bf[90000];
        static char msg[90000];
        char *s;

        ncpy(fname,file_tpl(xfname),BFSZ-1);

        tpl_init();
        f = fopen(fname,"r");
        if (f==NULL) {
                printf("Cannot open template {%s}<br>\n",fname);
#ifndef NOSTRERROR
                printf("%s<br>",strerror(errno));       
#endif
                return NULL;
        }

        strcpy(msg,"");
        for (;!feof(f);) {
                if (fgets(bf,BFSZ-10,f)==NULL) break;
                s = strchr(bf,'\n');
                if (s!=NULL) *s = 0;
                s = strchr(bf,'\r');
                if (s!=NULL) *s = 0;

                s = tpl_replace(bf);
                strcat(msg,s);
                strcat(msg,"\n");

        }
        return msg;
}
void tpl_show(char *xfname)
{
        FILE *f;
        char fname[BFSZ];
	char next_tpl[BFSZ];
        char bf[66000];
        char *s;

	ncpy(next_tpl,either_find("next_tpl"),200);
	if (strlen(next_tpl)>0) {
		if (strstr(next_tpl,"..")==NULL) 
		if (strstr(next_tpl,"/")==NULL) 
		if (strstr(next_tpl,"\\")==NULL) 
		if (strstr(next_tpl,".tpl")!=NULL) {
			xfname = next_tpl;
		}
	}
        dmsg("tpl_show called (%s)\n",xfname);

        tpl_init();
		
	strcpy(fname,file_tpl(xfname));
        
        dmsg("tpl_show called (%s)\n",fname);

        dmsg("tpl_show init done\n");
        f = fopen(fname,"r");
        if (f==NULL) {
                printf("Cannot open {%s} check your templates setting in dnewsweb.ini is correct and that this file is readable by the web server user code \n",fname);
#ifndef NOSTRERROR
                printf("%s<br>",strerror(errno));       
#endif
                return;
        }

        for (;!feof(f);) {
                if (fgets(bf,BFSZ-10,f)==NULL) break;
                s = strchr(bf,'\n');
                if (s!=NULL) *s = 0;
                s = strchr(bf,'\r');
                if (s!=NULL) *s = 0;

                s = tpl_replace(bf);
                if (strlen(s)>0) printf("%s\n",s);

        }
        dmsg("tpl_show done\n");
}
static int tpl_mode;
static char tpl_latest[10000];
static char tpl_item[10000];
static char tpl_dir[10000];
static char* tpl_indent_on[20];
static char* tpl_indent_off[20];
char *tpl_indenton(int i)
{
        if (i<0) return "";
        if (i>9) return "";
        if (tpl_indent_on[i]!= NULL) return tpl_indent_on[i];
        return "";
}
char *tpl_indentoff(int i)
{
        if (i<0) return "";
        if (i>9) return "";
        if (tpl_indent_off[i]!= NULL) return tpl_indent_off[i];
        return "";
}
enum {T_NORM,T_ITEM,T_DIR,T_LIST,T_IF,T_GROUPS,T_GSEARCH,T_GROUP_LIST,T_LATEST};
void tpl_setindent(char *s)
{
        int i;
        /* %%indent%%1%%on%%off%% */
        int n;
        char *s2;
        char *s3,*s4;

        s += 10;
        n = atoi(s); if (n<0) return;
        if (n>9) return;
        s2 = strstr(s,"%%"); if (s2==NULL) return;
        s2 += 2;
        s3 = strstr(s2,"%%"); if (s3==NULL) return;
        *s3 = 0;
        s3 += 2;
        s4 = strstr(s3,"%%"); if (s4==NULL) return;
        *s4 = 0;
        tpl_indent_on[n] = mystrdup(s2,M_LIB);
        tpl_indent_off[n] = mystrdup(s3,M_LIB);
        for (i=n+1; i<10; i++) {
                if (tpl_indent_on[i]==NULL) {
                        tpl_indent_on[i] = "";
                        tpl_indent_off[i] = "";
                }
        }
        return;
}
char *int_str(int i)
{
        static char bf[BFSZ];
        sprintf(bf,"%d",i);
        return bf;
}
void tpl_set_buttons(void)
{
        char bf[BFSZ];
        if (gfrom>group_from) { 
                sprintf(bf,"%s?cmd=xover&group=%s&from=%d&utag=%s",path_script,towww(group),gfrom-gmax,utage);
                var_set("b_prev",bf);
                var_set("from_down",int_str(gfrom-gmax));
        }
        imsg("tpl_set_buttons (%d<%d)  (%d>%d)\n",gto,group_to,gfrom,group_from);
        if (gto<group_to) { 
                sprintf(bf,"%s?cmd=xover&group=%s&from=%d&forward=TRUE&utag=%s",path_script,towww(group),gto,utage);
                var_set("b_next",bf);
                var_set("from_up",int_str(gto));
                sprintf(bf,"%s?cmd=xover&group=%s&utag=%s",path_script,towww(group),utage);
                var_set("b_recent",bf);
        } 
        if (strlen(utage)>0) {
                sprintf(bf,"%s?cmd=user&utag=%s",path_script,utage);
        } else {
                sprintf(bf,"%s?cmd=list&utag=%s",path_script,utage);
        }
        var_set("b_topgroups",bf);
        sprintf(bf,"%s?cmd=listall&utag=%s",path_script,utage);
        var_set("b_allgroups",bf);
        sprintf(bf,"%s?cmd=post&group=%s&utag=%s",path_script,towww(group),utage);
        var_set("b_post",bf);
        sprintf(bf,"%s?cmd=f_find&group=%s&utag=%s",path_script,towww(group),utage);
        var_set("b_search",bf);
}
void tpl_set_gl(void);

void tpl_init(void)
{
        char bf[BFSZ];
        
        char *ord = user_get("sort");


        tpl_mode = T_NORM;
        user_read(utag);
        if (strlen(ord)==0) ord = ini_get(I_SORT_ORDER);
        if (strlen(ord)==0) ord = "Thread";
        var_set("sort_order",ord);
        if (strlen(ini_get(I_POP_HOST))>0) var_set("pop_host",ini_get(I_POP_HOST));
        if (isquery) var_set("isquery","TRUE");
        if (strlen(utag)>0) {
                var_set("loggedin","true");
        }
        if (ini_true(I_POP_AUTHENT)) var_set("pop_authent","true");
        imsg("set utag = (%.80s) \n",utag);
        var_set("utag",utag);
        var_set("utage",utage);
        var_set("udom",udom);
        var_set("user",guser);
	if (ini_true(I_TOMAIL)) var_set("tomail","true");
        strcpy(tpl_item,"");
        if (strlen(utage)>0) {
                sprintf(bf,"%.200s?cmd=user&utag=%.100s",path_script,utage);
        } else {
                sprintf(bf,"%.200s?cmd=list&utag=%.100s",path_script,utage);
        }
        var_set("b_topgroups",bf);
        sprintf(bf,"%.200s?cmd=listall&utag=%.200s",path_script,utage);
        var_set("b_allgroups",bf);
        sprintf(bf,"%.200s?cmd=xover&utag=%.200s",path_script,utage);
        var_set("b_group",bf);
        sprintf(bf,"%s",path_script);
        var_set("b_action",bf);
        sprintf(bf," <FONT SIZE=-2> \n <a href=\"http://netwinsite.com/\"> DNEWSWEB %s Copyright &copy; <I>NetWin Ltd</I>\n </a></FONT> ",DNEWS_VERSION,path_script);
        var_set("copyright",bf);

        ncpy(topname,query_find("top"),BFSZ-1);
        if (strlen(topname)==0) {
                ncpy(topname,form_find("top"),BFSZ-1);
        }
        if (strlen(topname)==0) strcpy(topname,"top.tpl");
        var_set("top",topname);

        ncpy(tplname,query_find("tpl"),BFSZ-1);
        if (strlen(tplname)==0) {
                ncpy(tplname,form_find("tpl"),BFSZ-1);
        }
        if (strlen(tplname)==0) strcpy(tplname,"");
        var_set("tpl",tplname);

        ncpy(group,query_find("group"),BFSZ-200);
        var_set("group",group);
        if (strlen(group)==0) {
                ncpy(group,form_find("group"),BFSZ-1);
                var_set("group",group);
        }

        sprintf(bf,"%.200s?cmd=r_subscribe&group=%.200s&utag=%.200s",path_script,towww(group),utage);
        var_set("b_subscribe",bf);
        sprintf(bf,"%.200s?cmd=f_find&group=%.200s&utag=%.200s",path_script,towww(group),utage);
        var_set("b_searchgrp",bf);
        var_set("action",path_script);
        if (strlen(ini_get(I_SEARCH))>0) {
                sprintf(bf,"%.200s?cmd=f_search&utag=%.200s",path_script,utage);
                var_set("b_search",bf);
        }
        sprintf(bf,"%.200s?cmd=post&group=%.200s&utag=%.200s",path_script,towww(group),utage);
        var_set("b_post",bf);

	tpl_set_gl();

}
/*
        Add options like
                %%if var_name
                        xxxx
                %%endif
*/

int tpl_get_latest_groups(char *groups)
{
    char bf[BFSZ];
    char temp[BFSZ];
    char *s;
    int i;
    ncpy(bf,groups,BFSZ-10);
    s=strtok(bf,", ");
    if (s!=NULL) {
    	    sprintf(temp,"%.200s?cmd=xover&group=%.200s",path_script,towww(s));
	    var_set("primary_group_ref",temp);
	    var_set("primary_group",value_encode(s));
	    /*printf("primary_group_ref (%s) primary_group (%s)\n",temp,value_encode(s));*/
    }
    for (;s!=NULL;)
    {
	group_add(s);
	s=strtok(NULL,", ");
    }
    return TRUE;
}

char *tpl_replace(char *bf)
{
        char *s,*s2;
        char var[BFSZ]; 
        char head[BFSZ];        
        char list[BFSZ];
        
        static int lvl;
		/*imsg("Calling replace with [%s]\n",bf);*/

        switch (tpl_mode) {
	  case T_LATEST:
		if (strcmp(bf,"%%end_list%%")==0)
		{
		    tpl_mode = T_NORM;
                    tpl_show_latest();
                }
		else
		    strcat(tpl_latest,bf);
		break;
          case T_IF:
                if ((strncmp(bf,"%%ifdef%%",9)==0) || (strncmp(bf,"%%ifgroup%%",9)==0)|| (strncmp(bf,"%%ifcgi%%",9)==0)) {
                        lvl++;
                } else if (strcmp(bf,"%%endif%%")==0) {
                        lvl--;
                        if (lvl==0) tpl_mode = T_NORM;
                }
                if (lvl==1) if (strcmp(bf,"%%else%%")==0) tpl_mode = T_NORM;
                break;
          case T_NORM:
                if (strncmp(bf,"%%auth_username%%",17)==0) {
                        s = bf+17;
                        s2 = strstr(s,"%%");
                        if (s2==NULL) return bf;
                        ncpy(auth_username,s,s2-s);
                        return "";
                }
                else if (strncmp(bf,"%%body_lines%%",14)==0) {
                        s = bf+14;
			s2= strstr(s,"%%");
			if (s2==NULL) return bf;
			ncpy(var,s,s2-s);
			body_lines = atoi(var);
			return ""; 
		} else if (strncmp(bf,"%%items_per_group%%",19)==0) {
			s = bf+19;
			s2 = strstr(s,"%%");
			if (s2==NULL) return bf;
			ncpy(var,s,s2-s);
			items_per_group = atoi(var);
			return "";
		} else if (strncmp(bf,"%%groups_to_show%%",18)==0) {
			s = bf+18;
                        s2 = strstr(s,"%%");
                        if (s2==NULL) return bf;
	                ncpy(var,s,s2-s);
			tpl_init();
			tpl_get_latest_groups(var);
			return "";
    		} else if (strcmp(bf,"%%begin_list%%")==0) {
			tpl_mode = T_LATEST;
			strcpy(tpl_latest,"");
			return "";
		} else if (strcmp(bf,"%%begin_item%%")==0) {
                        tpl_mode = T_ITEM;
                        strcpy(tpl_item,"");
                        return "";
                } else if (strcmp(bf,"%%begin_groups%%")==0) {
                        tpl_mode = T_GROUPS;
                        strcpy(tpl_groups,"");
                        return "";
                } else if (strcmp(bf,"%%begin_group_list%%")==0) {
                        tpl_mode = T_GROUP_LIST;
                        strcpy(tpl_groups,"");
                        return "";
                } else if (strcmp(bf,"%%begin_gsearch%%")==0) {
                        tpl_mode = T_GSEARCH;
                        strcpy(tpl_groups,"");
                        return "";
                } else if (strncmp(bf,"%%else%%",9)==0) {
                        tpl_mode = T_IF;
                        lvl = 1;
                } else if (strncmp(bf,"%%ifdef%%",9)==0) {
                        /* %%if%%var%% */
                        s = bf+9;
                        s2 = strstr(s,"%%");
                        if (s2==NULL) return bf;
                        ncpy(var,s,s2-s);
                        if ((strcmp(var_find(var),"")==0) || (strcmp(var_find(var),"false")==0)) {
                                tpl_mode = T_IF;
                                lvl = 1;
                                dmsg("Variable undefined {%s}\n",var);
                        } else dmsg("Variable is defined {%s}\n",var);
                } else if (strncmp(bf,"%%ifgroup%%",11)==0) {
                        s = bf+11;
                        s2 = strstr(s,"%%");
                        if (s2==NULL) return bf;
                        ncpy(var,s,s2-s);
                        if (!group_match(var,group)) {
                                tpl_mode = T_IF;
                                lvl = 1;
                                dmsg("Group didn't match  {%s} {%s}\n",var,group);
                        } else dmsg("Group matched {%s} {%s}\n",var,group);
                } else if (strncmp(bf,"%%ifcgi%%",9)==0) {
                        s = bf+9;
                        s2 = strstr(s,"%%");
                        if (s2==NULL) return bf;
                        ncpy(head,s,s2-s);
                        s = s2+2;
                        s2 = strstr(s,"%%");
                        if (s2==NULL) return bf;
                        ncpy(list,s,s2-s);
                        imsg("ifhead Test (%s) (%s) (%s)\n",list,head,mygetenv(head));
                        if (!group_match(list,mygetenv(head))) {
                                tpl_mode = T_IF;
                                lvl = 1;
                                imsg("ENV didn't match  {%s} {%s}\n",list,mygetenv(head));
                        } else imsg("ENV matched {%s} {%s}\n",list,mygetenv(head));
                } else if (strncmp(bf,"%%include%%",11)==0) {
                        s = bf+11;
                        s2 = strstr(s,"%%");
                        if (s2==NULL) return bf;
                        ncpy(var,s,s2-s);
                        tpl_show_file(var);
                } else if ((s=strstr(bf,"%%quote_body%%"))!=NULL) {
			s2=s+14;
			*s=0;
			printf(bf);
			tpl_quote_body();
			printf(s2);
                        return "";
                } else if (strcmp(bf,"%%show_item_image%%")==0) {
                        tpl_show_item_image();
                        return "";
                } else if (strcmp(bf,"%%show_item%%")==0) {
                        tpl_show_item();
                        return "";
                } else if (strcmp(bf,"%%begin_dir%%")==0) {
                        tpl_mode = T_DIR;
                        return "";
                } else if (strncmp(bf,"%%indent%%",10)==0) {
                        tpl_setindent(bf);
                        return "";
                } else return tpl_replace_vars(bf);
                break;
          case T_ITEM:
                if (strcmp(bf,"%%end_item%%")==0) {
                        tpl_mode = T_NORM;
                        tpl_show_group();
                        return "";
                }
                strcat(tpl_item,bf);
                break;          
          case T_GROUPS:
                if (strcmp(bf,"%%end_groups%%")==0) {
                        tpl_mode = T_NORM;
                        tpl_show_groups();
                        return "";
                }
                strcat(tpl_groups,bf);
                break;          
          case T_GROUP_LIST:
                if (strcmp(bf,"%%end_group_list%%")==0) {
                        tpl_mode = T_NORM;
                        tpl_show_group_list();
                        return "";
                }
                strcat(tpl_groups,bf);
                break;          
          case T_GSEARCH:
                if (strcmp(bf,"%%end_gsearch%%")==0) {
                        tpl_mode = T_NORM;
                        tpl_show_gsearch();
                        return "";
                }
                strcat(tpl_groups,bf);
                break;          
          case T_DIR:
                if (strcmp(bf,"%%end_dir%%")==0) {
                        tpl_mode = T_NORM;
                        tpl_show_list();
                        return "";
                }
                break;          
        }
        return "";
}
char *get_cookie(char *var)
{
        char *s;
        char *s2;
        static char orig[5001];
        s = mygetenv("HTTP_COOKIE");
        if (strlen(s)==0) s = mygetenv("COOKIE");
        if (strlen(s)==0) {
		imsg("No cookies defined\n");
		return "";
	}
        ncpy(orig,s,5000);
        imsg("Searching cookie (%s) (%s) \n",var,orig);
        s = strtok(orig,";");
        for (;s!=NULL;) {
                for (;*s==' ';) s++;
                s2 = strchr(s,'='); if (s2==NULL) continue;
                *s2 = 0;
                if (strcmp(s,var)==0) return s2+1;
                s = strtok(NULL,";");
        }
        return "";

}

static char *var_names[200];
static char *var_values[200];
static int nvar;
char *var_find(char *var)
{
        int i;
        for (i=0; i<nvar; i++) {
                if (strcmp(var_names[i],var)==0) return var_values[i];
        }
        if (strncmpnc(var,"e_",2)==0) {
                return mygetenv(var+2);
        }
        if (strncmpnc(var,"cookie_",7)==0) {
                return get_cookie(var+7);
        }
        return "";
}
void var_set(char *var, char *val)
{
        int i;
        char *s;
        if (val==NULL) return;
        for (i=0; i<nvar; i++) {
                if (strcmp(var,var_names[i])==0) {
                        myfree(var_values[i]);
                        goto setit;
                }
        }
        i = nvar++;
        var_names[i] = mystrdup(var,M_LIB);
setit:
        var_values[i] = mystrdup(val,M_LIB);
        if (strlen(var_values[i]) > 60000) {
                s = var_values[i];
                s[60000] = 0;
        }
}
char *tpl_replace_vars(char *orig)
{
        char var[BFSZ];
        char *s=orig;
        char *s2;
again:
        s = strstr(s,"%%");
        if (s==NULL) return orig;
        s += 2;
        s2 = strstr(s,"%%");
        if (s2==NULL) return orig;
        ncpy(var,s,s2-s);
        tpl_replace_var(s-2,(s2+2) - (s-2) ,var_find(var));
        s -= 2;
        goto again;
}
void tpl_replace_var(char *bf, int len, char *var)
{
        int nlen = strlen(var);    
        memmove(bf+nlen,bf+len,strlen(bf+len)+1);
        strncpy(bf,var,nlen);
}
int ref_find(char *ref)
{       
        int i;
        int j;
        char bf[BFSZ];
        int np;
        char *p[1000];
        ncpy(bf,ref,BFSZ-10);
        np = token_split(bf,p," ",800);

        for (j=np-1; j>=0; j--) {
                for (i=0; i<nitem; i++) {
                        if (strcmp(p[j],x_mid[i])==0) return i;
                }
        }
        return -1;
}
int ref_depth(char *ref)
{
        char bf[BFSZ];
        char *s;
        int tot;
        ncpy(bf,ref,BFSZ-1);
        s = strtok(bf," ");
        for (tot=1; s!=NULL; tot++) {
                s = strtok(NULL," ");
        }
        if (tot>9) tot = 9;
        return tot;
}

static int rev = 1;
/*
Subject sort
        Primary number is item number of first matching subject
        plus 1/n 
Sort by item number no sort.
        primary number = n
*/
enum {SRT_THREAD,SRT_SUBJECT,SRT_DATE};
int srt_order(void)
{
        int o;
        char bf[BFSZ];
        char *ord = user_get("sort");
        user_read(utag);
        if (strlen(ord)==0) ord = ini_get(I_SORT_ORDER);
        ncpy(bf,ord,BFSZ-1); strlwr(bf);
        o = SRT_THREAD;
        if (strcmp(bf,"subject")==0) o = SRT_SUBJECT;
        if (strcmp(bf,"date")==0) o = SRT_DATE;
        return o;
}
char *do_spaces(int z)
{
        static char bf[5000];
        int i;
        if (strlen(ini_get(I_SPACES))==0) {
                memset(bf,' ',z);
                bf[z] = 0;
                return bf;
        }
        strcpy(bf,"");
        for (i=0; (i<z) && (strlen(bf)<3000); i++) {
                strcat(bf,ini_get(I_SPACES));
        }
        return bf;

}
int subj_cmp(char *s1, char *s2)
{
        char bf1[BFSZ]; 
        char bf2[BFSZ];
        ncpy(bf1,s1, BFSZ-1);
        ncpy(bf2,s2, BFSZ-1);
        s1 = bf1; s2 = bf2;
        if (strncmpnc(s1,"re: ",4)==0) s1+=4;
        if (strncmpnc(s2,"re: ",4)==0) s2+=4;
        if (strncmpnc(s1,"re:",3)==0) s1+=3;
        if (strncmpnc(s2,"re:",3)==0) s2+=3;
        if (strncmpnc(s1,s2,30)==0) return TRUE;
        return FALSE;
}

void tpl_show_latest(void)
{
    int i;
    char *s,*e;
    char bf[5000];
    char temp[BFSZ];
    char temp2[BFSZ];
    char item[BFSZ];
    int item2;
    int item3;
    char item4[BFSZ];
    
    if (!open_status()) {zmsg("tpl_show_latest1: News host not responding: %s",nntp_status); return;}
    if (strlen(auth_username)>0) {
        /* authenticate using the username defined in latest.tpl.
        e.g. %%auth_username%%fred%% issue xdauthent domain fred tellnews_pass
        */
        if (!do_latest_authent()) {
            zmsg("tpl_show_latest2: News host authentication failed: %s",nntp_status);
            return;
        }
    }
    if (items_per_group==0) items_per_group = 1;
    for (i=0;i<ngroups;i++) {
	sprintf(temp,"group %s\015\012",groups[i].name);
	nntp_write_s(chan,temp,strlen(temp)); 
	if (!read_status()) {zmsg("tpl_show_latest3: News host not responding: %s",nntp_status); continue;}
	/* get last article number - fourth number in the group response */
	s=strchr(nntp_status,' '); s=strchr(++s,' '); s=strchr(++s,' ');
	e=strchr(++s,' '); if (e!=NULL) *e=0;
	ncpy(item,s,BFSZ-10);
	for(item2=0;item2<items_per_group;item2++) {
	    item3 = atoi(item)-item2;
	    if (item3<0) {
		imsg("tpl_show_latest: not displaying latest article (%s)(%d)(%d-%d)< %%items_per_group%% items in group\n",groups[i].name,item3,atoi(item),item2);
		break;
	    }
	    sprintf(temp2,"article %d\015\012",item3);
	    nntp_write_s(chan,temp2,strlen(temp2)); 
	    if (!read_status()) {zmsg("tpl_show_latest4: News host not responding: %s",nntp_status); continue;}
	    read_xover();	
	    tpl_set_latest_vars();
	
            /* set variables involving group/item numbers */
            sprintf(temp,"%s?cmd=xover&group=%s&utag=%s",path_script,towww(groups[i].name),utage);
            var_set("group_ref",temp);
	    var_set("group",value_encode(groups[i].name));
	    sprintf(item4,"%d",item3);
            var_set("item",value_encode(item4));
            sprintf(temp,"%s?cmd=article&group=%s&item=%s&utag=%s",path_script,towww(groups[i].name),value_encode(item4),utage);
            var_set("item_ref",temp);
	
	    ncpy(bf,tpl_latest,6000);
	    s = tpl_replace_vars(bf);
	    printf("%s",s);
	}
    }
}

void tpl_show_group(void)
{
        int p[9000]; 
        char bf[60000];
        char bf2[60000];
        char *s;
        int repeat;
        int nloop=0;
        int j;
        int i2;
        int z;
        int depth,d,newdepth;
        int i,ii;
        double px,py;   
        int ord = srt_order();
        rev = -1;
        if (strcmp("false",ini_get(I_SORT_REV))==0) rev = 1;
        if (nitem>=MAX_ITEMS) nitem = MAX_ITEMS-10;

        imsg("Show_group %d items\n",nitem);
        for (i=0; i<nitem; i++) p[i] = i;
        for (i=0; i<nitem; i++) x_f[i] = -9999;
        if (ord==SRT_SUBJECT) {
         for (i=0; i<nitem; i++) {
                x_f[i] = i*rev;
                if (strlen(x_ref[i])>0) {
                        x_depth[i] = ref_depth(x_ref[i]);
                /*imsg("depth[%d] = %d\n",i,x_depth[i]);*/
                } 
                for (j=0; j<i; j++) {
                        if (subj_cmp(x_subject[j],x_subject[i])) {
				if (rev<0) {
	                                x_f[i] = x_f[j]+1.0-(1.0/(i+1));
				} else {
	                                x_f[i] = x_f[j]+(1.0/(i+1));
				}
                                /*imsg("subject: x_f[%d] = %g\n",i,x_f[i]);*/
                                break;
                        }
                }
         }
         goto dosort;
        }
        if (ord==SRT_DATE) {
         for (i=0; i<nitem; i++) {
                x_f[i] = rev*i;
         }
         goto dosort;
        }
        
        imsg("Show_group_2 %d items\n",nitem);
        for (i=0; i<nitem; i++) {
                x_fi[i] = i;
                if (strlen(x_ref[i])>0) {
                        x_depth[i] = ref_depth(x_ref[i]);
                        j = ref_find(x_ref[i]);
                        if (j>=0) x_fi[i] = j; 
                        else x_f[i] = rev*i;
                } else x_f[i] = rev*i;
                /* dmsg("[%d] points to %d\n",i,x_fi[i]);*/
        }
        imsg("Show_group_3 %d items\n",nitem);
        for (repeat=TRUE;repeat && (nloop<10);nloop++) {
          repeat = FALSE;
          for (i=0; i<nitem; i++) {
                if (x_f[i] == -9999) {
                        py = x_depth[i];
                        if (py<0) py = 0;
                        if (py>7) py = 7;
                        px = pow(40,py);
                        if (px<=1) px = 1;
                        if (x_f[x_fi[i]] == -9999) repeat = TRUE;
                        else {
                                if (px==0) px = 1;      
                                x_f[i] = x_f[x_fi[i]] + ((double) i)/(double) px;
                                if (x_f[i] > pow(40,8)) x_f[i] = pow(40,8);
                        }
                        /* if (x_f[i]<0) repeat = TRUE;*/
/*dmsg("[%d] set to %d = %g %g [%g]+%g %g\n",i,x_fi[i],x_f[i],(double) pow(50,x_depth[i]),x_f[x_fi[i]],i/(double) pow(50,x_depth[i]),(double) pow(50,(double) x_depth[i]))*/
                } 
          }
        }
dosort:
        imsg("Show_group_5 %d items\n",nitem);
        if (!search_result) {
                if (nitem>2) qsort(p,nitem,sizeof(int),xover_cmp);
                printf("%s",tpl_indenton(1));
        }
        depth = 1;
        imsg("Show_group_6 %d items\n",nitem);
        for (i=0; i<nitem; i++) {
                ii = p[i];
imsg("Loop %d %d \n",i,ii,x_item[ii]);

                if (i>0) i2 = p[i-1];
                if (search_result) goto skip;
                
                newdepth = ref_depth(x_ref[ii]);
                if (newdepth<2) {
                        if (strncmpnc(x_subject[ii],"re:",3)==0) newdepth=2;
                }
                if (i==0) newdepth = 1;
                if (newdepth!=1) {
                  if (rev) {
                    if (((int) (x_f[ii]-0.99999999)) != ((int) (x_f[i2]-0.99999999))) {
                          newdepth = 1;
                    }
                  } else {
                    if (((int) x_f[ii]) != ((int) x_f[i2])) {
                          newdepth = 1;
                    }
                  }
                }
                if (newdepth>9) newdepth = 9;
                for (d = depth+1; d <= newdepth; d++) {
                        printf("%s",tpl_indenton(d));
                }
                for (d = depth; d > newdepth; d--) {
                        printf("%s",tpl_indentoff(d));
                }
                depth = newdepth;
skip:   
                if (x_group[ii]!=NULL) if (strlen(x_group[ii])>0) {
                        strcpy(bf2,x_group[ii]);
                        s = strchr(bf2,':');
                        if (s!=NULL) {
                                *s = 0; s++;
                                strcpy(group,bf2);
                                x_item[ii] = atoi(s);
                                goto skip2;
                        }
                }
skip2:                  
                var_set("h_group",value_encode(group));
                sprintf(bf,"%s?cmd=article&group=%s&item=%d&utag=%s",path_script,towww(group),x_item[ii],utage);
                var_set("b_item",bf);

                var_set("item_n",pad_right(int_str(x_item[ii]),3));
		if (strlen(x_subject[ii])==0) var_set("h_subject",value_encode("(No subject)"));
                else var_set("h_subject",value_encode(x_subject[ii]));
/*sprintf(bf,"%g %s",x_f[ii],value_encode(x_subject[ii]));
var_set("h_subject",bf);
*/
                if (depth>1) {
                        z = (depth-1) * 1;
                        if (z>10) z=10;
                        memset(bf,'-',z);
                        bf[z] = '>';
                        bf[z+1] = 0;
                        var_set("arrows",value_encode(bf));
                } else var_set("arrows","");
                if (depth>1) {
                        z = (depth-1) * 1 + 1;
                        if (z>10) z=10;
                        var_set("spaces",do_spaces(z));
                } else var_set("spaces","");

                var_set("h_from",value_encode(x_from[ii]));
                var_set("h_message-id",value_encode(x_mid[ii]));
                var_set("h_lines",x_lines[ii]);
                var_set("h_bytes",x_bytes[ii]);
                var_set("h_score",x_score[ii]);
                var_set("h_date",value_encode(x_date[ii]));
                var_set("h_date_trim",value_encode(h_date_trim(x_date[ii])));
		/* brian123*/
		var_set("h_date_numeric",value_encode(h_date_numeric(x_date[ii])));
                var_set("h_from_trim",value_encode(h_from_trim(x_from[ii])));
                var_set("h_subject_60",value_encode(h_trim(x_subject[ii],60)));
                var_set("h_subject_40",value_encode(h_trim(x_subject[ii],40)));
                var_set("h_subject_30",value_encode(h_trim(x_subject[ii],30)));

		if (atoi(x_bytes[ii]) >atoi(ini_get(I_ISBINARY_SIZE))) {
			var_set("isbinary",ini_get(I_ISBINARY_IMG));
			var_set("istext","");
		} else {
			var_set("istext",ini_get(I_ISTEXT_IMG));
			var_set("isbinary","");
		}
                strcpy(bf,tpl_item);
                if (!group_allow_silent(group)) continue;

                s = tpl_replace_vars(bf);
                printf("%s\n",s);
        }
        imsg("Show_group done\n");
        if (search_result) return;
        for (d = depth; d > 1; d--) {
                printf("%s",tpl_indentoff(d));
        }
        printf("%s",tpl_indentoff(1));
}
/*
x y <a@b>       = x y
a@b             = a
a@b (name)      = name
*/
char *h_from_trim(char *s)
{
        static char bf[BFSZ];
        char *s2;
        strcpy(bf,s);
        /* a@b (name) */
        s = strchr(bf,'(');
        if (s!=NULL) { 
                s2 = strchr(s,')');
                if (s2==NULL) return bf;
                *s2 = 0;
                return s+1;
        }
        /* x y <a@b> = x y*/
        s = strchr(bf,'<');
        if (s!=NULL) {
         for (s=bf;*s!=0; s++) if (!xisspace(*s)) break;
         if (*s!='<') {
                s2 = strchr(s,'<');
                if (s2==NULL) return bf;
                *s2 = 0;
                return s;
         } else {       /* <a@b>*/
                s2 = strchr(s,'>');
                if (s2==NULL) return bf;
                *s2 = 0;
                return s+1;
         }
        }
        if (strchr(bf,'@')==NULL) return bf;

        /*a@b*/
        for (s=bf;*s!=0; s++) if (!xisspace(*s)) break;
        for (s2=s;*s2!=0;s2++) if (xisspace(*s2)) break;
        *s2 = 0;
        return s;
}
char *h_trim(char *s, int len)
{
        static char bf[BFSZ];
        ncpy(bf,s,len);
        if (strlen(s)>len) strcat(bf,"*");
        return bf;
}
/* Tue, 3 Jan 98 23:33:33 GMT */
/* 3 Jan 93 */

char *h_date_trim(char *instr) 
{
        static char bf[BFSZ];
        char *s;
        s = strchr(instr,',');
        if (s==NULL) s = instr; else s++;
        for (;*s==' ';) s++;
        strcpy(bf,s);
        s = strchr(bf,' '); if (s==NULL) return bf;
        s = strchr(s+1,' '); if (s==NULL) return bf;
        s = strchr(s+1,' '); if (s==NULL) return bf;
        *s = 0;
        return bf;
}

char* month_n(char *month) {
    char bf[BFSZ];
    char *m;

    ncpy(bf,month,10);
    strlwr(bf);
    m="1";
    if (strncmp(month,"jan",3)==0) m="1";
    else if (strncmp(bf,"feb",3)==0) m="2";
    else if (strncmp(bf,"mar",3)==0) m="3";
    else if (strncmp(bf,"apr",3)==0) m="4";
    else if (strncmp(bf,"may",3)==0) m="5";
    else if (strncmp(bf,"jun",3)==0) m="6";
    else if (strncmp(bf,"jul",3)==0) m="7";
    else if (strncmp(bf,"aug",3)==0) m="8";
    else if (strncmp(bf,"sep",3)==0) m="9";
    else if (strncmp(bf,"oct",3)==0) m="10";
    else if (strncmp(bf,"nov",3)==0) m="11";
    else if (strncmp(bf,"dec",3)==0) m="12";
    
    return m;
}

/* Tue, 3 Jan 98 23:33:33 GMT */
/* 3.1.98 23:33 */
char *h_date_numeric(char *instr)
{
    
    char bf[BFSZ];
    char *bf2;
    static char numdate[BFSZ];
    char stuff[8][100];
    int i;
    bf2 = strchr(instr,',');
    if (bf2==NULL) bf2 = instr; else bf2++;
    ncpy(bf,bf2,100);
    ncpy(numdate,"date",10);
    for(i=0;i<8;i++) ncpy(stuff[i],"",90);
    bf2=strtok(bf," ,:");
    for(i=0;i<6;i++) {
    	if (bf2==NULL) break;
	ncpy(stuff[i],bf2,90);
	bf2=strtok(NULL," ,:");
    }
    sprintf(numdate,"%s.%s.%s %s:%s",stuff[0],month_n(stuff[1]),stuff[2],stuff[3],stuff[4]);
    return numdate;    
}

void tpl_show_list(void)
{
        show_dlist();

}
void tpl_show_top(void)
{
        printf("show list of top news groups\n");
}

void show_raw(void)
{
    int item = atoi(query_find("item"));
    printf("Content-type: text/plain\n\n");
    printf("%s",str_s(instr));
    imsg("tpl_show_raw(%d)\n",str_len(instr));
}

void show_article(void)
{ 
        int part = atoi(query_find("part"));
        if (part>0) { 
                imsg("Show article part\n");
                show_article_part(part);        
                imsg("Show article part done\n");
                return;
        }
        tpl_init_item();
        tpl_show("item.tpl");
}
static char boundary[BFSZ];
static int isimage = FALSE;
static char mime[BFSZ];
static char xhtml[BFSZ];
static char encoding[BFSZ];
static char i_subject[BFSZ];
static char i_content[BFSZ];
void get_attach_name(char *in);
static char attach_name[BFSZ];
void tpl_init_item(void)
{
        char *s,*x;
        char subject[BFSZ];
        static char from[BFSZ];
        static char date[BFSZ];
        static char ref[BFSZ];
        static char mid[BFSZ];
        static char organization[BFSZ];
        static char content[BFSZ];
	static char nntpposthost[BFSZ];
        char bf[BFSZ];
        char *s2;
        int gothead = FALSE;
        int multi,got,istext;
        char newsgroups[BFSZ];
	char newsgroups_space[BFSZ];
	char temp[BFSZ];
	char *i;

        int item = atoi(query_find("item"));
        int related = item;

        if (b_item>=0) item = related = b_item;


        multi = got = istext = FALSE;
        strcpy(subject,"");
        strcpy(from,"");
        strcpy(date,"");
        strcpy(organization,"");
        strcpy(newsgroups,"");
	strcpy(newsgroups_space,"");
	strcpy(nntpposthost,"");
        related = item;

        if (docache) printf("Pragma: cache\n");
        printf("Content-type: %s\n\n",content_type());
        done_content = TRUE;
        strcpy(attach_name,"attach.jpg");
        var_set("group",group);
        var_set("item",int_str(item));
        sprintf(bf,"%s?cmd=xover&group=%s&related=%d&utag=%s",path_script,towww(group),related,utage);
        var_set("b_related",bf);
        sprintf(bf,"%s?cmd=xover&group=%s&utag=%s",path_script,towww(group),utage);
        var_set("b_recent",bf);
        if (strlen(utage)>0) {
                sprintf(bf,"%s?cmd=user&utag=%s",path_script,utage);
        } else {
                sprintf(bf,"%s?cmd=list&utag=%s",path_script,utage);
        }
        var_set("b_topgroups",bf);
        sprintf(bf,"%s?cmd=listall&utag=%s",path_script,utage);
        var_set("b_allgroups",bf);
        sprintf(bf,"%s?cmd=post&group=%s&utag=%s",path_script,towww(group),utage);
        var_set("b_post",bf);
        sprintf(bf,"%s?cmd=follow&group=%s&item=%d&utag=%s",path_script,towww(group),item,utage);
        var_set("b_follow",bf);
	sprintf(bf,"%s?cmd=raw&group=%s&item=%d&utag=%s",path_script,towww(group),item,utage);
        var_set("item_raw",bf);

        if (!gothead) s = get_line_head(instr);
        else s = get_line(instr);
        for (;s!=NULL;) {
                if (strcmp(s,"")==0) break; /*bazil*/
                head_get("subject:",subject,s);
                if (ini_true(I_NON_ASCII)) ncpy(subject,rfc1522s(subject),BFSZ-10);
		head_get("date:",date,s);
                head_get("message-id:",mid,s);
                head_get("from:",from,s);
		if (ini_true(I_NON_ASCII)) ncpy(from,rfc1522s(from),BFSZ-10);
                head_get("organization:",organization,s);
                head_get("references:",ref,s);
                head_get("newsgroups:",newsgroups,s);
                head_get("mime-version:",mime,s);
                head_get("x-html:",xhtml,s);
                head_get("content-type:",content,s);
                head_get("content-transfer-encoding:",encoding,s);
		head_get("nntp-posting-host:",nntpposthost,s); /*brianabc*/
                get_attach_name(s);
                s2 = strstr(s,"boundary=");
                if (s2==NULL) s2 = strstr(s,"Boundary=");
                if (s2!=NULL) {
                        s2 = strchr(s2,'"');
                        strcpy(boundary,"--");
                        if (s2!=NULL) ncpy(boundary+2,s2+1,BFSZ-10);
                        s2 = strchr(boundary,'"');
                        if (s2!=NULL) *s2 = 0;
                }
	        if (!gothead) s = get_line_head(instr);
                else s = get_line(instr);
        }
	/* variable newsgroups_space with comma followed by space as newsgroup delimter */
	ncpy(temp,newsgroups,BFSZ-100);
	*newsgroups_space=0;
	for(i=strtok(temp,",");i!=NULL;) {
	    strcat(newsgroups_space,i);
	    if ((i=strtok(NULL,","))!=NULL) strcat(newsgroups_space,", ");
	}
        var_set("h_from",value_encode(from));
        var_set("h_references",eoltospace(value_encode(ref)));
        var_set("h_subject",value_encode(subject));
        if (strlen(subject)==0) var_set("h_subject",value_encode("(No subject)"));

	var_set("h_organization",value_encode(organization));
	var_set("h_date",value_encode(date));
	/* 29.09.1999 13:35 brian123*/
	var_set("h_date_numeric",value_encode(h_date_numeric(date)));
        var_set("h_message-id",value_encode(mid));
        var_set("h_newsgroups",value_encode(newsgroups));
	var_set("h_newsgroups_space",value_encode(newsgroups_space));
        var_set("h_content-type",value_encode(content));
	ncpy(i_subject,subject,300);
	ncpy(i_content,content,300);
	var_set("h_nntp-posting-host",value_encode(nntpposthost)); /* brianabc */
        strlwr(content);
        if (strlen(xhtml)==0) if (strstr(content,"text/html")!=NULL) strcpy(xhtml,content);
}

void tpl_set_latest_vars(void)
{
        char *s,*x;
        char subject[BFSZ];
        static char from[BFSZ];
        static char date[BFSZ];
        static char ref[BFSZ];
        static char mid[BFSZ];
        static char organization[BFSZ];
        static char content[BFSZ];
	static char body[11000];
	int lines = 0;
	int body_total = 0;
        char bf[BFSZ];
        char *s2;
        int gothead = FALSE;
        char newsgroups[BFSZ];

        strcpy(subject,"");
        strcpy(from,"");
        strcpy(date,"");
        strcpy(organization,"");
        strcpy(newsgroups,"");
	strcpy(body,"");

        if (!gothead) s = get_line_head(instr);
        else s = get_line(instr);
        for (;s!=NULL;) {
                if (strcmp(s,"")==0) gothead=TRUE; /*bazil*/
		if (!gothead) {
		    head_get("newsgroups:",group,s);
		    head_get("subject:",subject,s);
                    if (ini_true(I_NON_ASCII)) ncpy(subject,rfc1522s(subject),BFSZ-10);
		    head_get("date:",date,s);
		    head_get("message-id:",mid,s);
		    head_get("from:",from,s);
		    if (ini_true(I_NON_ASCII)) ncpy(from,rfc1522s(from),BFSZ-10);
		    head_get("organization:",organization,s);
		    head_get("references:",ref,s);
		    head_get("newsgroups:",newsgroups,s);
		    head_get("mime-version:",mime,s);
		    head_get("x-html:",xhtml,s);
		    head_get("content-type:",content,s);
		    head_get("content-transfer-encoding:",encoding,s);
		}
	        else {
		    body_total += strlen(s);
		    if (body_total>10000) break;
		    if (body_lines>0) if (lines++>body_lines) {
			if (ini_true(I_FORMAT_HTML))
			    strcat(body,"...<br>");
			else
			    strcat(body,"...\n");
			break;
		    }
		    strcat(body,show_text_fn(s));
		}
		if (!gothead) s = get_line_head(instr);
                else s = get_line(instr);
        }
	var_set("h_group",value_encode(group));
        var_set("h_from",value_encode(from));
        var_set("h_references",eoltospace(value_encode(ref)));
        var_set("h_subject",value_encode(subject));
        if (strlen(subject)==0) var_set("h_subject",value_encode("(No subject)"));
	var_set("h_organization",value_encode(organization));
	var_set("h_date",value_encode(date));
	/* brian 12/10/99 */
        var_set("h_date_trim",value_encode(h_date_trim(date)));
        var_set("h_message-id",value_encode(mid));
        var_set("h_newsgroups",value_encode(newsgroups));
        var_set("h_content-type",value_encode(content));
        strlwr(content);
        if (strlen(xhtml)==0) if (strstr(content,"text/html")!=NULL) strcpy(xhtml,content);
	var_set("body",body);
}

char *quote_encode(char *s);
void tpl_quote_body(void)
{ 
        char *s;
        int skip_encoding = 0;
        int skip_next = 0;

        if (instr==NULL) return;
	s = strchr(from,'\015'); 
        if (s!=NULL) *s = 0;
        
	if (ini_true(I_NON_ASCII)) printf("%s wrote:\n",rfc1522s(from));
	else printf("%s wrote:\n",from);	
	
        if (*ini_get(I_KEEP_FORMATING) == 't'){
                s = str_s(instr);
                if (s==NULL) return;
                s+=gupto;
                JLLformat_wrap_output(JLLcomment_write_s, s, atoi(ini_get(I_WRAP_TEXT)));
        }else{
                s = get_line(instr);
                for (;s!=NULL;) {
                        if (skip_next) { skip_next = 0; goto skipit; };
                        if (strncmpnc(s,"Content-Transfer-Encoding: base64",33)==0) skip_encoding = 1;
                        if (skip_encoding>0) if (strlen(s)==1) skip_encoding++;
                        if (skip_encoding>2) skip_encoding = 0;
                        if (skip_encoding==1) goto skipit; 
                        if (s[0]=='M') if (strlen(s)==62) goto skipit;
                        /* brian - skip some of the common MIME headers */
                        if ((strncmpnc(s,"Content-Transfer-Encoding:",26)==0) ||
                           (strncmpnc(s,"Content-Type:",13)==0) ||
                           (strncmpnc(s,"Content-Disposition:",20)==0))
                        {
                            if (s[strlen(s)-1]==';') skip_next = 1;
                            goto skipit;
                        };
                        if (strncmpnc(s,"This is a multi-part message in MIME format.",44)==0) goto skipit;
                        /* if this is mime then skip the boundaries as detected in show_article1() */
                        if (strlen(mimeboundary)!=0) if (strstr(s,mimeboundary)!=NULL) goto skipit;                        
                        /* brian - removed rfc1522 encoding only applies in headers
                        if (ini_true(I_NON_ASCII)) printf("%s",rfc1522s(quote_encode(s)));
                        else*/
                        printf("%s\n",quote_encode(s));
skipit:                 s = get_line(instr);
                }
        }
}
char *quote_encode(char *s)
{
        static char bf[4000];
        int i;
        char *out=bf;
        int len;
        int w = atoi(ini_get(I_WRAP_TEXT));
        w -= 8;
        if (w<=0) w = 1000;
        len = 0;
        *out++ = '>';
        for (i=0; (i<2000) && (*s!=0);i++,s++,len++) {
                if (*s=='\n') len = 0;
                if (*s=='\r') len = 0;
                if (len>w) {
                        if (xisspace(*s)) {
                                *out++ = '\n';
                                *out++ = '>';
                                len = 0;
                                continue;
                        }
                } 
                *out++ = *s;
        }
        *out++ = 0;
        return bf;
}


/*
        For clarinet *.web groups

  <img src='*clari.net  --> <img src='news:*clari.net
  <a href='*clari.net'  --> <a href='news:*clari.net'
*/
char *str_sanitize(char *s) /* Remove spaces and unsavory macintosh crap */
{
        static char bf[BFSZ];
        char *out=bf;
        for (;*s!=0;s++) {
                if (isalnum(*s) || (*s=='.') || (*s=='_')) *out++ = *s;
                if (*s=='/') out=bf;
                if (*s=='\\') out=bf;
        }
        *out++ = 0;
        return bf;
}
void get_attach_name(char *in)
{
        char *s;
        if (strncmp(in,"content-",8)!=0) return;
        s = strstr(in,"name="); if (s==NULL) return;
        imsg("get attach processing %s\n",s);
        s += 5;
        for (;*s!=0;s++) if (!xisspace(*s)) break;
        if (*s=='"') s++;
        ncpy(attach_name,s,BFSZ-1);
        s = strchr(attach_name,'"'); 
        if (s!=NULL) *s = 0;
        else {
                s = strchr(attach_name,' '); if (s!=NULL) *s = 0;
        }
        ncpy(attach_name,str_sanitize(attach_name),BFSZ-1);
        if (strlen(attach_name)==0) strcpy(attach_name,"noname.jpg");
        imsg("get attach set %s\n",attach_name);
}
char *savename(char *s)
{
	if (ini_true(I_REMOVE_NAME)) return "";
	return s;
}
char *clari_encode(char *ss);
void tpl_show_item_image(void)
{
        int item = atoi(query_find("item"));
        if (b_item>=0) item = b_item;

        strlwr(encoding);
        printf("<img src=\"%s/%s?cmd=article&group=%s&item=%d&part=200&utag=%s\"><br>",path_script,savename(attach_name),towww(group),item,utage);
}
static int nbound;
static char *bound[200];

void boundary_add(char *s)
{
        char *s2;
        char *start;
        char bf[BFSZ];
        s2 = strstr(s,"boundary=");
        if (s2==NULL) s2 = strstr(s,"Boundary=");
        if (s2==NULL) s2 = strstr(s,"BOUNDARY=");
        if (s2!=NULL) {
                start = s2;
                strcpy(bf,"--");
                s2 = strchr(s2,'"');
                if (s2!=NULL) {
                        ncpy(bf+2,s2+1,BFSZ-10);
                        s2 = strchr(bf,'"');
                        if (s2!=NULL) *s2 = 0;
                } else {
                        ncpy(bf+2,start+9,BFSZ-10);
                        s2 = strchr(bf,';');
                        if (s2!=NULL) *s2 = 0;
                        s2 = strchr(bf,' ');
                        if (s2!=NULL) *s2 = 0;
                }
                bound[nbound++] = strdup(bf);
                imsg("Boundary added (%s)\n",bf);
        }
}
static int endbound;
int boundary_check(char *in)
{

        int i;
        endbound = FALSE;
        for (i=0; i<nbound; i++) {
                if (strncmp(in,bound[i],strlen(bound[i]))==0) {
                 if (strncmp("--",in+strlen(bound[i]),2) ==0) {
                        imsg("end of boundary\n");
                        endbound = TRUE;
                 } else {
                        imsg("Boundary matched (%s) \n",bound[i]);
                 }
                 return TRUE;
                }
        }
        return FALSE;
}

void tpl_show_item(void)
{
        int uucount;
	int uucontent = FALSE; /* brian */
	static int multi;
        int istext = FALSE;
        int ishtml = FALSE;
        char *x;
        int ismsg = FALSE;
        int gothead = FALSE;
        int isquoted=FALSE;
        int isref = FALSE;
        char *z;
        int isbase64=FALSE;
        char bf[BFSZ];
        int got;
        char *s;
        int item = atoi(query_find("item"));
        char *s2;
	char subject[BFSZ];
	int parti,partmax;
	char fname[BFSZ];
	int first_line= TRUE;
	int r;
        int israw = FALSE;
        char custom_href[BFSZ];
        char *t;
        int isbase64text=FALSE;
	int isvcard = FALSE;
	char b0[BFSZ];
	char b1[BFSZ];
	char b2[BFSZ];
	char b3[BFSZ];
        
        /* get any cutomisation to put in the <a href's */
        ncpy(custom_href,"",0);
        if (strlen(ini_get(I_LINK_ADD))>0) {
            t=strchr(ini_get(I_LINK_ADD),'%');
            if (t==NULL) sprintf(custom_href," %.500s",ini_get(I_LINK_ADD));
            else emsg("tpl_show_item: dnewsweb.ini LINK_ADD setting invalid remove %%\n");
        }
        
        if (strstr(content_type(),"text")!=NULL) isbase64text=TRUE;

        if (b_item>=0) item = b_item;

        imsg("tpl_show_item(%d)\n",str_len(instr));
        strlwr(encoding);
        multi = FALSE;
        if (strlen(xhtml)>0) israw = TRUE;
        if (strlen(mime)>0) if (strlen(boundary)>0) multi = TRUE;
                
                if (!multi) if (strstr(encoding,"base64")!=NULL) {
                        /* not all that is base64 coded is an image! */
                        if (!isbase64text) {
                           printf("<img src=\"%s/%s?cmd=article&group=%s&item=%d&part=99&utag=%s\"><br>",path_script,savename(attach_name),towww(group),item,utage);
                           goto endbit;
                        }
        }
        got = 0;
        if (multi) {
	  if (!gothead) s = get_line_head(instr);
          else s = get_line(instr);

          for (;s!=NULL;) {
                s2 = strchr(s,'\015') ; if (s2!=NULL) *s2 = 0; s2 = strchr(s,'\012') ; if (s2!=NULL) *s2 = 0;
                if ((strstr(s,boundary)!=NULL) || boundary_check(s)) {
/*			if (isvcard) printf("</pre>");*/

                        if (!pre_disable) if (istext) if (!ishtml) printf("</pre>\n"); 
                        gothead = FALSE; istext = FALSE; got++;
                        isimage = FALSE; isbase64 = FALSE;
                        ismsg = FALSE; ishtml = FALSE;
			isvcard = FALSE;
			uucount=0; /*brian*/
			uucontent=FALSE; /*brian*/
                }
		if (!gothead) if (strlen(s)==0) {
                        if (ismsg)  { /* double header */
                                ismsg = FALSE;
                                goto next_line;
                        }
                        if (!(isimage||isbase64||ishtml||uucontent)) istext=TRUE; /*bazil*/
			imsg("show part istext %d................\n",istext);
                        if (istext) { 
                                if (!pre_disable) if (!ishtml) printf("<pre>\n");
                                else printf("<hr>");
                        }
			gothead = TRUE;
			
			/*if (isvcard) printf("<pre>");*/
			if ((isimage) && (!uucontent)) /*brian*/ {
                                imsg("show image part=%d\n",got);
			        printf("<img src=\"%s/%s?cmd=article&group=%s&item=%d&part=%d&utag=%s\"> <br>",path_script,savename(attach_name),towww(group),item,got,utage);
                        } else 
                          if (isbase64) {
                                imsg("show attachment part=%d\n",got);
                                printf("<P><a%s href=\"%s/%s?cmd=article&group=%s&item=%d&part=%d&utag=%s&/%s\">%s</a><P>",custom_href,path_script,savename(attach_name),towww(group),item,got,utage,attach_name,attach_name);
                        } else if (isvcard) {
                                printf("<P><a%s href=\"%s/%s?cmd=article&group=%s&item=%d&part=%d&utag=%s&/%s\">%s</a><P>",custom_href,path_script,savename(attach_name),towww(group),item,got,utage,attach_name,attach_name);
				istext = FALSE;
			}
			goto next_line;
                }
/* Content-Type: message/rfc822*/
                
                if (!gothead) {
                        /* printf("%s<br>\n",s);*/
                        boundary_add(s);
                        strlwr(s);
                        if (strstr(s,"message/rfc822")!=NULL) ismsg = TRUE;
                        if (strstr(s,"text/")!=NULL) istext = TRUE;
                        if (strstr(s,"image/")!=NULL) isimage = TRUE;
                        if (strstr(s,"text/html")!=NULL) ishtml = TRUE;
                        if (strstr(s,"base64")!=NULL) isbase64 = TRUE;
                        if (strstr(s,"quoted-printable")!=NULL) isquoted = TRUE;
                        if (strstr(s,"text/x-vcard")!=NULL) isvcard = TRUE; 
			/* brian */
			if (strstr(s,"x-uuencode")!=NULL) uucontent = TRUE;
			if (strstr(s,"x-uue")!=NULL) uucontent = TRUE;
                        get_attach_name(s);
                } else {
                       /* brian */
		       if (uucontent) {
			    goto munged_uuencoding;
		       }
finished_uu_munging:   /* brian */
                       if(!uucontent) if (istext) {  /*brian - was ishtml*/
                                if (isquoted) {
                                    /*imsg("DECODING quoted_printable data '%s'\n",s);*/
                                    printf("%s",decode_quote(s));
                                    /*imsg("DECODED quoted_printable data '%s'\n",decode_quote(s));*/
                                }
                                else if (isbase64) printf("%s",decode_base64s(s));
                                else printf("%s",s);
/*				if (isvcard) printf("\n");*/
                       } else if ((istext)&&(!isbase64)) { /* brian */
			        if (*ini_get(I_KEEP_FORMATING) == 't')
                                        JLLformat_wrap_output(JLLtext_encode, s, atoi(ini_get(I_WRAP_TEXT)));
                                else
				    show_text(s);
                       }
                }
next_line:    
	        if (!gothead) s = get_line_head(instr);
		else s = get_line(instr);
          }
          goto endbit;
        }

	gothead = TRUE;
        if (!pre_disable) if (!israw) printf("<pre>\n");
        if (!gothead) s = get_line_head(instr);
	else s = get_line(instr);
        isimage = FALSE; 
	uucontent = FALSE; /* brian */
        uucount = 0;
        isquoted = strstr(encoding,"quoted-printable")!=NULL;
        isbase64 = strstr(encoding,"base64")!=NULL;
munged_uuencoding: /* brian */
	for (;s!=NULL;) {
		if (first_line) {
			first_line = FALSE;
			if (*s=='M') if (str_len(instr)>20000) {
			  if (parts_subject(i_subject,subject,fname,&parti,&partmax)) {
				imsg("Subject is (%s)\n",i_subject);
				imsg("Looks like part %d of %d, fname=(%s), subj=(%s)\n",parti,partmax,fname,subject);
				printf("<a href=\"%s/%s?cmd=parts&group=%s&item=%d&partmax=%d&subj=%s&utag=%s&/%s\">Re-assemble multipart attachment: %s</a><p>",path_script,lib_encode_more(b0,fname),towww(group),item,partmax,lib_encode_more(b1,subject),utage,lib_encode_more(b2,fname),fname);
				isimage = TRUE;
			  }
			}
			strlwr(i_content);
			if (strstr(i_content,"partial")!=NULL) {
			  if (parts_subject(i_subject,subject,fname,&parti,&partmax)) {
				imsg("Found mime Subject is (%s)\n",i_subject);
				imsg("Looks like part %d of %d, fname=(%s), subj=(%s)\n",parti,partmax,fname,subject);
				printf("<a href=\"%s/%s?cmd=parts&group=%s&item=%d&partmax=%d&subj=%s&utag=%s&/%s\">Re-assemble multipart attachment: %s</a><p>",path_script,lib_encode_more(b0,fname),towww(group),item,partmax,lib_encode_more(b1,subject),utage,lib_encode_more(b2,fname),fname);
				isimage = TRUE;
			  } else {
				imsg("Looked like mime but wasn't %s\n",i_content);	  
			  }
			}
		}
		first_line = FALSE;
                if (strncmp(s,"begin ",6)==0) {
			uucount++;
                        ncpy(bf,s,BFSZ-1);
                        isref = FALSE;
                        x = strtok(bf," \012\015"); if (x==NULL) goto skip;
                        x = strtok(NULL," \012\015"); if (x==NULL) goto skip;
                        if (atoi(x)<100) goto skip;
                        x = strtok(NULL," \012\015"); if (x==NULL) goto skip;
                        strlwr(x);
                        if (strchr(x,'.')==NULL) {
                                x = strtok(NULL," \012\015"); if (x==NULL) goto skip;
                        }
			isref=TRUE;
                        if (strstr(x,".jpg")!=NULL) {isref=FALSE;strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".jpeg")!=NULL) {isref=FALSE;strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".gif")!=NULL) {isref=FALSE;strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".avi")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".mpg")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".mpeg")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".zip")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".exe")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".doc")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".xls")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".com")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".txt")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".ini")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".log")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".html")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".htm")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        if (strstr(x,".pdb")!=NULL) {isref = TRUE; strcpy(attach_name,x); goto isok;}
                        z = strstr(x,".");
                        if (z!=NULL) if (strlen(z+1)>=1) {isref = TRUE; strcpy(attach_name,x); goto isok;}      
                        goto skip;

isok:                   isimage = TRUE;
                        /* brian */
			if (multi) {
			    if (!isref) 
				printf("<img src=\"%s/%s?uucount=%d&cmd=article&group=%s&item=%d&part=%d&utag=%s\"><br>",path_script,savename(attach_name),uucount,towww(group),item,got,utage);
                            else {
                                if (ini_true(I_NON_ASCII)) printf("<a%s href=\"%s/%s?uucount=%d&cmd=article&group=%s&item=%d&part=%d&utag=%s&/%s\">%s</a><p>",custom_href,path_script,savename(attach_name),uucount,towww(group),item,got,utage,attach_name,rfc1522s(attach_name));
                                else printf("<a%s href=\"%s/%s?uucount=%d&cmd=article&group=%s&item=%d&part=%d&utag=%s&/%s\">%s</a><p>",custom_href,path_script,savename(attach_name),uucount,towww(group),item,got,utage,attach_name,attach_name);
                            }
			}
			else {	
			  r = parts_subject(i_subject,subject,fname,&parti,&partmax);
			  if (r && (partmax>1)) {
				imsg("Subject is (%s)\n",i_subject);
				imsg("Looks like part %d of %d, fname=(%s), subj=(%s)\n",parti,partmax,fname,subject);
				printf("<a href=\"%s/%s?cmd=parts&group=%s&item=%d&partmax=%d&subj=%s&utag=%s&/%s\">Re-assemble multipart attachment: %s</a><p>",path_script,lib_encode_more(b0,fname),towww(group),item,partmax,lib_encode_more(b1,subject),utage,lib_encode_more(b2,fname),fname);
				isimage = TRUE;
			  } else {				
			    if (!isref) 
				printf("<img src=\"%s/%s?uucount=%d&cmd=article&group=%s&item=%d&part=100&utag=%s\"><br>",path_script,savename(attach_name),uucount,towww(group),item,utage);
                            else {
                                if (ini_true(I_NON_ASCII)) printf("<a%s href=\"%s/%s?uucount=%d&cmd=article&group=%s&item=%d&part=100&utag=%s&/%s\">%s</a><p>",custom_href,path_script,savename(attach_name),uucount,towww(group),item,utage,attach_name,rfc1522s(attach_name));
                                else printf("<a%s href=\"%s/%s?uucount=%d&cmd=article&group=%s&item=%d&part=100&utag=%s&/%s\">%s</a><p>",custom_href,path_script,savename(attach_name),uucount,towww(group),item,utage,attach_name,attach_name);
                            }
			  }
			}
                }
skip:
		/* brian */
		if (uucontent) goto finished_uu_munging;
                if (!israw) {
                    if (!isimage) if (!isref)
                        if (*ini_get(I_KEEP_FORMATING) == 't') {
                            if (isquoted) JLLformat_wrap_output(JLLtext_encode, decode_quote(s), atoi(ini_get(I_WRAP_TEXT)));
                            else JLLformat_wrap_output(JLLtext_encode, s, atoi(ini_get(I_WRAP_TEXT)));
                        }
                        else {
                            if (isquoted) show_text(decode_quote(s));
                            else if (isbase64) {
                                        if (isbase64text)
                                            printf("%s",text_encode(decode_base64text(s)));
                                        else
                                            printf("%s",text_encode(decode_base64s(s)));
                                }
                                else show_text(s);
                        }
                } else {
                        printf("%s",clari_encode(s));
                }
                if (isimage) {
                        if (strncmp(s,"end",3)==0) isimage = FALSE;
                }
	        if (!gothead) s = get_line_head(instr);
                else s = get_line(instr);
        }
        if (!pre_disable) if (!israw) printf("</pre>\n");
endbit:;

}
void show_text(char *s)
{
	int r;
	if (!format_html) {printf("%s\n",text_encode(s)); return; }
	r = strspn(s,"\r\n \t");
	if (r==strlen(s)) printf("<p>\n");
	else if (*s=='>') printf("<br>\n");
	printf("%s ",text_encode(s));	
}

char *show_text_fn(char *s)
{
	int r;
	static char bf[10000];
	if (!format_html) {
	    sprintf(bf,"%s\n",text_encode(s)); return bf;
	}
	r = strspn(s,"\r\n \t");
	strcpy(bf,"");
	if (r==strlen(s)) strcat(bf,"<p>\n");
	else if (*s=='>') strcat(bf,"<br>\n");
	strcat(bf,text_encode(s));	
	strcat(bf," ");
	return bf;
}

void clari_insert(char *s, char *in);
void clari_insert(char *s, char *in)
{
        memmove(s+strlen(in),s,strlen(s)+1);
        strncpy(s,in,strlen(in));
}
char *clari_encode(char *ss)
{
        char *s2;
        char *s=ss;
again:
        s = strstr(ss,"<IMG SRC=\'");
        if (s!=NULL) {
                s2 = strchr(s,':');
                if (s2==NULL) {clari_insert(s+10,"news:"); goto again;}
                if ((s2-s)>17) {clari_insert(s+10,"news:"); goto again;}
        }
        s = strstr(ss,"<A HREF=\'");
        if (s!=NULL) {
                s2 = strchr(s,':');
                if (s2==NULL) {clari_insert(s+9,"news:"); goto again;}
                if ((s2-s)>17) {clari_insert(s+9,"news:"); goto again;}
        }
        return ss;
}
/*  <img src='*clari.net  --> <img src='news:*clari.net
  <a href='*clari.net'  --> <a href='news:*clari.net'
*/

 
/*
Things to do:
        Change all output sections so they use the replace system.
        Threading algorithym
        Fix dnewsweb known bugs (allow etc...)
        Test all image combinations, allow html etc.
        Add     %%ifdef variable                to file
*/
#ifdef WIN32
char *nt_other(void)
{
        return "";
}
#endif
#ifdef NEED_STRERROR
extern int sys_nerr;
extern char *sys_errlist[];
char *strerror(int x)
{
      if ((x<sys_nerr) && (x>=0)) return sys_errlist[x];
      return "No error";
}
#endif
void fimsg(char * arg_list, ...)
{
}

char *cr_encode(char *s)
{
        char *o;
        static char out[5000];
        for (o=out;*s!=0;s++) {
                if (*s=='\n') {*o++ ='\\'; *o++ = 'n';}
                else if (*s=='\\') {*o++ ='\\'; *o++ = '\\';}
                else if (*s=='\r') continue;
                else *o++ = *s;
        }
        *o++ = 0;
        return out;
}
char *cr_decode(char *s)
{
        char *o;
        static char out[5000];
        for (o=out;*s!=0;s++) {
          if (*s=='\\') {
                s++;
                if (*s=='\\') {*o++ = '\\';}
                else if (*s=='n')  {*o++ = '\n';}
          } else *o++ = *s;
        }
        *o++ = 0;
        return out;
}
char *get_quote(char *s)
{
        static char bf[BFSZ];
        if (*s=='"') {
                ncpy(bf,s+1,BFSZ-1);
                s = strchr(bf,'"');
                if (s!=NULL) *s = 0;
        } else {
                ncpy(bf,s,BFSZ-1);
                s = strchr(bf,' ');if (s!=NULL) *s = 0;
                s = strchr(bf,';');if (s!=NULL) *s = 0;
                s = strchr(bf,',');if (s!=NULL) *s = 0;
                s = strchr(bf,'\n');if (s!=NULL) *s = 0;
        }
        return bf;
}
void cgi_addvar(char *name, char *value)
{
        char *s;
        if (strlen(name)==0) return;
        s = strdup(value);
imsg("cgi_addvar(%.40s) = len %d (%.40s)\n",name,strlen(value),value);
        if (strlen(s)>1) s[strlen(s)-2] = 0;
        form_val[nform] = s;
        form_name[nform++] = strdup(name);
        /* imsg("Variable added (%s) = (%s) \n",name,s);*/
        strcpy(name,"");
        strcpy(value,"");
}

char *pad_right(char *s, int n)
{
        static char bf[BFSZ];
        strcpy(bf,s);
        if (strlen(bf)>=n) return bf;
        memset(bf+strlen(s),' ',n);
        bf[n] = 0;
        return bf;
}


void r_xdebug(void)
{
	int i;
	zmsg("Debugging info %d %s<br>\n",dodebug,log_file);

	
	for (i=0; ini_names[i]!=NULL; i++) {
		if (strcmp(ini_names[i],"tellnews_pass")==0) continue;
		if (ini_values[i]!=NULL) zmsg("Config (%s) = (%s) <br>\n",ini_names[i],ini_values[i]);
        }

}


void tpl_set_gl(void)
{
	char bf[BFSZ];
	char nam[BFSZ];
        int i;
        for (i=0; i<nform; i++) {
		if (strncmp(form_name[i],"gl_",3)==0) {
			var_set(form_name[i],value_encode(form_val[i]));
			ncpy(bf,form_val[i],BFSZ-10);
			lib_encode(bf);
			sprintf(nam,"%s_r",form_name[i]);
			var_set(nam,bf);
		}
	}
        for (i=0; i<nquery; i++) {
		if (strncmp(query_name[i],"gl_",3)==0) {
			var_set(query_name[i],value_encode(query_val[i]));
			ncpy(bf,query_val[i],BFSZ-10);
			lib_encode(bf);
			sprintf(nam,"%s_r",query_name[i]);
			var_set(nam,bf);
		}
	}
}
/*

2156175 KORN - ISSUES - 02 - Korn - For You.mp3 (08/20)
2156176 Attn DrPenalty  - Veruca Salt - Seether.mp3 (09/16)
2156182 Attn DrPenalty  - Veruca Salt - Seether.mp3 (04/16)
2156183 Early Presents - Joy to the World - Nat King Cole.mp3 [03/06]

*/
	
void tomail_read_item(char *group, int item, char *mid, char *subj)
{
	char bf[BFSZ];
	char *s;
	if (!open_status()) {zmsg("News host not happy %s",nntp_status); return;}
	if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}
	sprintf(bf,"group %s\015\012",group); nntp_write_s(chan,bf,strlen(bf)); 
	if (!read_status()) {zmsg("News host group: %s",nntp_status); return;}

        sprintf(bf,"xover %d\015\012",item); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("News host not responding: %s",nntp_status); return;}
        read_xover();

		/* find first message-id in the references */
                s = get_line(instr);
		if (s==NULL) {zmsg("News host not responding thread: %s",nntp_status); return;}
                s = xstrtok(s,"\t");
                if (s!=NULL) s = xstrtok(NULL,"\t");	/* skip nntp response code*/
                if (s!=NULL) {				/* get subject*/
                        strlwr(s);
                        if (strncmp(s,"re:",3)==0)  s += 3; 
                        if (*s == ' ') s++;
                        ncpy(subj,s,BFSZ-1);
                }
                if (s!=NULL) s = xstrtok(NULL,"\t");	/*/ skip from*/
                if (s!=NULL) s = xstrtok(NULL,"\t");	/*/ skip date*/           
                if (s!=NULL) s = xstrtok(NULL,"\t");	/*/ skip mid */       
                if (s!=NULL) ncpy(mid,s,BFSZ-1);	/*/ get the message-id of the root thread*/
                if (s!=NULL) s = xstrtok(NULL,"\t");	/*/ get root mid */       
                if (s!=NULL) {
			if (s[0]=='<') 	ncpy(mid,s,BFSZ-1);	/*/ get the message-id of the root thread*/
			s = strchr(mid,' '); if (s!=NULL) *s = 0;
		}

                str_clear(instr);


}
void cmd_tomail_add_thread(void)
{
	char mid[BFSZ];
	char bf[BFSZ];
	int item;
	char group[BFSZ];
	char subj[BFSZ];

        item = atoi(query_find("item"));
        if (item==0) item = atoi(query_find("xrelated"));
        ncpy(group,query_find("group"),BFSZ-1);
        if (!group_allow(group)) {zmsg("Cannot read that group"); return;}
	strcpy(mid,""); strcpy(subj,"");
	tomail_read_item(group,item,mid,subj);
	if ((strlen(mid)==0) || (strlen(subj)==0)) {
		zmsg("No subject specified, so cannot follow thread");
		return;
	}
	imsg("tomail_add_thread %s %s %s\n",group,mid,subj);

	sprintf(bf,"xtomail add group=%s to=%s thread=%s subject=\"%s\"\015\012",
		group,rfc1522s(user_get("reply"))
		,mid,subj); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("News host group: %s",nntp_status); return;}
	var_set("group",group);
	var_set("to",rfc1522s(user_get("reply")));
	var_set("subject",subj);
	var_set("status",nntp_status);
	if (atoi(nntp_status)!=200) {
		tpl_show("tomail_bad.tpl");		
	}
	tpl_show("tomail_ok.tpl");
}
void cmd_tomail_add(void)
{
	char mid[BFSZ];
	char bf[BFSZ];
	int item;
	char group[BFSZ];
	char subj[BFSZ];

	if (!open_status()) {zmsg("News host not happy %s",nntp_status); return;}
	if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}
        ncpy(group,query_find("group"),BFSZ-1);
        if (!group_allow(group)) {zmsg("Cannot read that group"); return;}
	sprintf(bf,"group %s\015\012",group); nntp_write_s(chan,bf,strlen(bf)); 
	if (!read_status()) {zmsg("News host group: %s",nntp_status); return;}
	imsg("tomail_add %s %s\n",group,rfc1522s(user_get("reply")));

	sprintf(bf,"xtomail add group=%s to=%s\015\012",
		group,rfc1522s(user_get("reply"))); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("News host group: %s",nntp_status); return;}
	var_set("group",group);
	var_set("to",rfc1522s(user_get("reply")));
	var_set("status",nntp_status);
	if (atoi(nntp_status)!=200) {
		tpl_show("tomail_bad.tpl");		
	}
	tpl_show("tomail_ok.tpl");
}
void cmd_tomail_del(void)
{
	char mid[BFSZ];
	char bf[BFSZ];
	int item;
	char group[BFSZ];
	char subj[BFSZ];

	if (!open_status()) {zmsg("News host not happy %s",nntp_status); return;}
	if (!do_authent()) {zmsg("News host authentication failed: %s",nntp_status); return;}

        ncpy(group,query_find("group"),BFSZ-1);
        if (!group_allow(group)) {zmsg("Cannot read that group"); return;}
	sprintf(bf,"group %s\015\012",group); nntp_write_s(chan,bf,strlen(bf)); 
	if (!read_status()) {zmsg("News host group: %s",nntp_status); return;}
	imsg("tomail_del %s %s\n",group,rfc1522s(user_get("reply")));

	sprintf(bf,"xtomail del group=%s to=%s\015\012",
		group,rfc1522s(user_get("reply"))); nntp_write_s(chan,bf,strlen(bf)); 
        if (!read_status()) {zmsg("News host group: %s",nntp_status); return;}
	var_set("group",group);
	var_set("to",rfc1522s(user_get("reply")));
	var_set("status",nntp_status);
	if (atoi(nntp_status)!=200) {
		tpl_show("tomail_bad.tpl");		
	}
	tpl_show("tomail_del.tpl");
}
/*                else if (ispressed("cmd_tomail_add_thread")) cmd_tomail_add_thread();
                else if (ispressed("cmd_tomail_add")) cmd_tomail_add();
                else if (ispressed("cmd_tomail_del")) cmd_tomail_del();

*/

/* display the DNewsweb version number, ini file settings and other related information */
void display_info(char *epath) {
    char bf[BFSZ];
    char bf2[BFSZ];
    char bf3[BFSZ];
    char xroot[BFSZ];
    char xin[5000];
    char *last;
    FILE *f;
        int k;
    int i;
    char *s;

        if (!done_content) printf("Content-Type: text/html\n\n");
        if (!ini_true(I_SHOWINI)) {
                printf("showini currently disabled - to enable add 'showini true' setting in dnewsweb.ini<br>\n");
                return;
        };
        printf("<html>\n");
        printf("<head>\n");
        printf("<title>DNEWSWEB version %s - Netwin Ltd.</title>\n",DNEWS_VERSION);
        printf("</head>\n");
        printf("<body>\n");
        printf("<h2>DNEWSWEB version %s - Netwin Ltd.</h2><hr><br>\n",DNEWS_VERSION);
        printf("<table border=1>\n");
    db_setscript(mygetenv("SCRIPT_NAME"));
    sprintf(bf,"%s.ini",rootname);
    f = fopen(bf,"r");
    strcpy(bf3,bf);
    if (f==NULL) {
                printf("<tr><td>ini file not in working dir, searching in path {%s}</tr></td>\n",epath);
        strcpy(xroot,epath);
        last = xroot;
        for (s=xroot; *s!=0; s++) {
                        if (*s=='/') last = s;
            if (*s=='\\') last = s;
        }
        *last = 0;
        sprintf(bf,"%s/%s.ini",xroot,rootname);
        printf("<tr><td>Looking in (%s) for ini file</tr></td>\n",bf);
                f = fopen(bf,"r");
                strcpy(bf2,bf);
        }
        if (f==NULL) {
                sprintf(bf,"/etc/%s.ini",rootname);
                printf("<tr><td>Last resort, looking in (%s) for ini file</tr></td>\n",bf);
                f = fopen(bf,"r");
        }
    if (f==NULL) {
                printf("<tr><td>Unable to find ini file in <br> {%s}\n</tr></td>",bf3);
        printf("<tr><td>Also looked in {%s} <br> and {%s}</tr></td>\n",bf2,bf);
        } else {
                printf("<tr><td><h2>dnewsweb.ini</h2></tr></td>\n");
                printf("<tr><td>\n");
                for (;!feof(f);) {
                        if (fgets(xin,4000,f)!=NULL) {
                                printf("%.200s<br>\n",xin);
                        }
        } 
                printf("</tr></td>\n");
        fclose(f);      
        }
        printf("<tr><td><h2>environment variables</h2></tr></td>\n");
        printf("<tr><td>\n");
        for (i=0;environ[i]!=NULL;i++) {
                printf("%.200s<br>\n",environ[i]);
        }
        printf("</tr></td>\n");
        printf("<tr><td>To disable remove 'showini true' from dnewsweb.ini</tr></td>\n");
        printf("</table>\n");
        printf("</body>\n");
        printf("</html>\n");
}
