User:Antigng-bot/filldoi

#include <stdio.h>
#include <string.h>
#include <process.h>
#include <windows.h>
#include "mem.h"
#include "network.h"
#include "struct.h"
#include "convert.h"
#include "auth.h"
struct problemlist
{
	unsigned long pageid;
	struct problemlist *next;
};
struct neditargv
{
	const char *id;
	HTTP newtext;
	const char *time;
};
int threadc[1024];
SRWLOCK rwcs;
CRITICAL_SECTION tcs;
CRITICAL_SECTION hcs;
CRITICAL_SECTION fcs;
int threadnumber=0;
unsigned char action=0;
struct hashlist *hl=NULL;
struct problemlist *pbl=NULL;
const char *username=NULL;
const char *passwd=NULL;
const char *searchstring=NULL;
const char *ns=NULL;
int maxthread=256;
int doallpage=0;
struct hashlist *usernamelist;
struct hashlist *userrenamelist;
struct hashlist *baduserlist;
/*
const char *api_url="/api/rest_v1/data/citation/mediawiki/";
*/
const char *api_url="http://localhost:1970/api?format=mediawiki&search=";
static void displayerr(unsigned int code)
{
	if(~(code&0x1))
	{
		printf(
			"\tNo username.\n"
			"\t\tA valid username must be specified via \"-u\".\n"
			);
	}
	if(code&0x2)
	{
		printf(
			"\tUsername too long.\n"
			"\t\tThe username should not be longer than 64 bytes.\n"
			);
	}
	if(~(code&0x4))
	{
		printf(
			"\tNo query.\n"
			"\t\tEither a search string (via -s) or \"-a\" should be set.\n"
			);
	}
	if(code&0x8)
	{
		printf(
			"\tPassword too long.\n"
			"\t\tThe password should not be longer than 64 bytes.\n"
			);
	}
	if(~(code&0x10))
	{
		printf(
			"\tNo password.\n"
			"\t\tA valid password must be specified via \"-p\".\n"
			);
	}
	if(code&0x20)
	{
		printf(
			"\tSearch string too long.\n"
			"\t\tThe search string should not be longer than 128 bytes.\n"
			);
	}
	if(code&0x40)
	{
		printf(
			"\tns string too long.\n"
			"\t\tThe ns string should not be longer than 32 bytes.\n"
			);
	}
	return;
}
static int parsearg(int argc,const char *argv[])
{
	int cur_arg=0;
	unsigned int err=0;
	doallpage=0;
	for(cur_arg=1;cur_arg<argc;cur_arg++)
	{
		if(argv[cur_arg][0]=='-'&&((argv[cur_arg+1]&&argv[cur_arg+1][0]!='-')||argv[cur_arg][1]=='a'))
		{
			switch(argv[cur_arg][1])
			{
			case 'u':
				username=G2U(argv[cur_arg+1]);
				if(strlen(username)>64)
				{
					err|=0x2;
				}
				else
				{
					err|=0x1;
				}
				cur_arg++;
				break;
			case 'a':
				err|=0x4;
				doallpage=1;
				break;
			case 'p':
				passwd=argv[cur_arg+1];
				if(strlen(passwd)>64)
				{
					err|=0x8;
				}
				else
				{
					err|=0x10;
				}
				cur_arg++;
				break;
			case 's':
				searchstring=G2U(argv[cur_arg+1]);
				if(strlen(searchstring)>128)
				{
					err|=0x20;
				}
				else
				{
					err|=0x4;
				}
				cur_arg++;
				break;
			case 'n':
				ns=argv[cur_arg+1];
				if(strlen(ns)>32)
				{
					err|=0x40;
				}
				cur_arg++;
				break;
			case 'T':
				maxthread=atoi(argv[cur_arg+1]);
				if(maxthread<1||maxthread>1024) maxthread=32;
				cur_arg++;
				break;
			}
		}
	}
	if(!ns) ns="0";
	if(0x1+0x4+0x10==err) return 0;
	else
	{
		displayerr(err);
		return 1;
	}
}
static int smartedit(struct neditargv *p,const char *reason, const char *tags)
{
	HTTP res;
	char line[2048],url[4096]={0};
	char reason_e[512];
	char tags_e[256];
	char aft[1024],statusline[128];
	char cur_token[128];
	char err_type[8192];
	char *erm[]={"code"};
	char *erv[1];
	int find=0;
	int has_err=0,token_err=0,filtered=0;
	int retry=0;
	erv[0]=err_type;
	if(reason) URLEncode(reason,strlen(reason),reason_e,510);
	if(tags) URLEncode(tags,strlen(tags),tags_e,254);
	sprintf(url,"/w/api.php?action=edit&pageid=%s&basetimestamp=%s",p->id,p->time);
	find=sprintf(aft,"%s%s&summary=%s&bot=1&minor=1&nocreate=1&format=xml&token=",tags?"&tags=":"",tags?tags_e:"",reason_e);
	if(find<0) return -4;
	do
	{
		res=hopen();;
		while(1)
		{
			AcquireSRWLockShared(&rwcs);
			if(hastoken) break;
			else ReleaseSRWLockShared(&rwcs);
			Sleep(100);
		}		
		aft[find]=0;
		strcat(aft,token);
		ReleaseSRWLockShared(&rwcs);
		hrewind(p->newtext);
		if(smartpost(url,p->newtext,aft,8888,1,res))
		{
			hclose(res);
			return -1;
		}
		hgets(statusline,127,res);
		if(!strstr(statusline," 200"))
		{
			hclose(res);
			return -2;
		}
		skipresponseheader(res);
		filtered=token_err=has_err=0;
		while(!heof(res))
		{
			if(xmlparsetag(res,line)==XML_HAS_VALUE)
			{
				if(!strcmp(line,"error"))
				{
					has_err=1;
					xmlparsearg(res,1,erm,erv);
					if((!strcmp(err_type,"notoken"))||(!strcmp(err_type,"badtoken")))
					{
						token_err=1;
					}
					else if(!strcmp(err_type,"abusefilter-warning"))
					{
						filtered=1;
					}
					break;
				}
			}
		}
		if(token_err)
		{
			AcquireSRWLockExclusive(&rwcs);
			if(!strcmp(aft+find,cur_token)) hastoken=0;
			ReleaseSRWLockExclusive(&rwcs);
		}
		retry++;
		hclose(res);
	}while((token_err||filtered)&&(retry<3));
	if(has_err) return -3;
	else return 0;
}
struct hashlist *logtype;
struct hashlist *temptype;
static void ini_marks()
{
	logtype=hashini();
	str_hashadd(logtype,"url","url");
	str_hashadd(logtype,"pages","pages");
	str_hashadd(logtype,"title","title");
	str_hashadd(logtype,"publisher","publisher");
	str_hashadd(logtype,"publicationTitle","journal");
	str_hashadd(logtype,"volume","volume");
	str_hashadd(logtype,"issue","issue");
	str_hashadd(logtype,"author","author");
	str_hashadd(logtype,"DOI","doi");
	str_hashadd(logtype,"date","date");
	str_hashadd(logtype,"language","language");
	str_hashadd(logtype,"accessDate","accessdate");
	str_hashadd(logtype,"ISBN","isbn");
	str_hashadd(logtype,"contributor","author");
	str_hashadd(logtype,"ISSN","issn");
	str_hashadd(logtype,"PMID","pmid");
	str_hashadd(logtype,"PMCID","pmc");

	temptype=hashini();
	str_hashadd(temptype,"journalArticle","cite journal");
	str_hashadd(temptype,"conferencePaper","cite journal");
	str_hashadd(temptype,"book","cite book");
	str_hashadd(temptype,"bookSection","cite book");
	return ;
}

static int formattitlestyle(const char *in,char *out)
{
	int countin=0,countout=0,mathflag=0;
	char ch=0;
	/*
	char source[1024],dest[1024];
	int countsource=0;
	*/
	for(countin=0;;countin++)
	{
		ch=in[countin];
		if(!ch) break;
		if(ch=='$')
		{
			switch(mathflag)
			{
			case 0:
				mathflag=1;
				strcpy(out+countout,"<math>");
				countout+=6;
				/*
				countsource=0;
				source[0]=0;
				*/
				break;
			case 1:
				mathflag=0;
				/*
				source[countsource]=0;
				if(formatlatex(source,dest))
				{
					out[countout]=0;
					return -2;
				}
				strcpy(out+countout,dest);
				countout+=strlen(dest);
				*/
				strcpy(out+countout,"</math>");
				countout+=7;
				break;
			}
		}
		/*
		else if(mathflag)
		{
			source[countsource++]=ch;
			if(countsource>1023)
			{
				out[countout]=0;
				return -4;
			}
		}
		*/
		else if((ch=='|')&&!mathflag)
		{
			strcpy(out+countout,"{{!}}");
			countout+=5;
		}
		else out[countout++]=ch;
	}
	out[countout]=0;
	if(mathflag) return -1;
	else return 0;
}
static int verifycite(const char *line,int reftype,const char *base)
{
	char str[65536];
	char decap_line[65536],decap_base[2048];
	int count=0,countbase=0;
	int state=0;
	for(count=0;line[count];count++)
	{
		decap_line[count]=(line[count]>='A'&&line[count]<='Z')?line[count]+'a'-'A':line[count];
	}
	decap_line[count]=0;
	for(count=0,countbase=0;base[count];count++)
	{
		if(!state)
		{
			if((base[count]=='<')&&(reftype==1)) state=1;
			else decap_base[countbase++]=(base[count]>='A'&&base[count]<='Z')?base[count]+'a'-'A':base[count];
		}
		else if(base[count]=='>') state=0;
	}
	decap_base[countbase]=0;
	switch(reftype)
	{
	case 1:
		sprintf(str,"doi=%s",decap_base);
		if(strstr(decap_line,str)) return 1;
		break;
	case 2:
		sprintf(str,"pmid=%s",decap_base);
		if(strstr(decap_line,str)) return 2;
		break;
	}
	return 0;
}
static int catcite(const char *ori_name,const char *value,char *line,int *linepos)
{
	char *fixed_name=NULL;
	if(!str_hashquery(logtype,ori_name,&fixed_name))
	{
		return 0;
	}
	if(!strcmp(fixed_name,"isbn")||!strcmp(fixed_name,"issn"))
	{
		char *p=strchr(value,',');
		if(p)
		{
			*p=0;
		}
	}
	strcat(line,"|");
	strcat(line,fixed_name);
	strcat(line,"=");
	if(!strcmp(fixed_name,"title"))
	{
		char fixed_value[65536];
		if(formattitlestyle(value,fixed_value))
		{
			return 2;
		}
		strcat(line,fixed_value);
		(*linepos)+=strlen(fixed_name)+strlen(fixed_value)+2;
	}
	else 
	{
		strcat(line,value);
		(*linepos)+=strlen(fixed_name)+strlen(value)+2;
	}
	if((*linepos)>=32768)
	{
		return 3;
	}
	return 0;
}
static int cite_post_process(HTTP res,const char *basedoi,char *citation,int reftype)
{
	int state=-1;
	char line[65536];
	int linepos=0;
	char name[256],value[65536];
	char *cur=name,*tempname=NULL;
	int curpos=0;
	int maxpos=64;
	int unicode=0,unicodecount=0;
	int bracount=0;
	int error=0;
	int setkey=0,setsource=0;
	line[0]=0;
	while(!heof(res))
	{
		char ch=hgetc(res);
		switch(state)
		{
		case -1:
			switch(ch)
			{
			case '\"':
				state=0;
				break;
			case '[':
				bracount++;
				break;
			case ']':
				bracount--;
				break;
			case ':':
				if(bracount>1)
				{
					cur[curpos++]=':';
					cur[curpos]=0;
				}
				else
				{
					cur=value;
					value[0]=0;
					curpos=0;
					maxpos=32768;
				}
				break;
			case ',':
				switch(bracount)
				{
				case 1:
					if(name[0]&&value[0])
					{
						if(!strcmp(name,"itemType"))
						{
							if(!str_hashquery(temptype,value,&tempname))
							{
								error=1;
								goto _errorplace;
							}
						}
						else if(!strcmp(name,"key"))
						{
							if(!setkey) setkey=1;
							else
							{
								if(verifycite(line,reftype,basedoi)) goto _cleanup;
								else
								{
									line[0]=0;
									linepos=0;
								}
							}
						}
						else
						{
							error=catcite(name,value,line,&linepos);
							if(error)
							{
								goto _errorplace;
							}
						}
					}
					cur=name;
					curpos=0;
					name[0]=0;
					maxpos=64;
					break;
				case 2:
					cur[curpos++]=',';
					cur[curpos++]=' ';
					cur[curpos]=0;
					break;
				default:
					cur[curpos++]=' ';
					cur[curpos]=0;
					break;
				}
				break;
			}
			break;
		case 0:
			if(ch=='\\') state=1;
			else if(ch=='\"')
			{
				cur[curpos]=0;
				state=-1;
			}
			else cur[curpos++]=ch;
			break;
		case 1:
			switch(ch)
			{
			case 'u':
				unicode=0;
				unicodecount=0;
				state=2;
				break;
			case '\\':
				cur[curpos++]='\\';
				state=0;
				break;
			case '\"':
				cur[curpos++]='\"';
				state=0;
				break;
			case 't':
				cur[curpos++]='\t';
				state=0;
				break;
			case 'r':
				cur[curpos++]='\r';
				state=0;
				break;
			case 'n':
				cur[curpos++]='\n';
				state=0;
				break;
			default:
				error=4;
				goto _errorplace;
			}
			break;
		case 2:
			ch=decoding[(unsigned char)ch];
			if(ch)
			{
				unicode=(unicode>>4)+ch-1;
				unicodecount++;
			}
			else
			{
				error=5;
				goto _errorplace;
			}
			if(unicodecount==4)
			{
				if(unicode>0x07FF)
				{
					char a,b,c;
					a=(char)((unicode & 64) +128);
					b=(char)(((unicode >> 6) & 64) +128);
					c=(char)((unicode >> 6) +224);
					cur[curpos++]=c;
					cur[curpos++]=b;
					cur[curpos++]=a;
				}
				else if(unicode>0x007F)
				{
					char a,b;
					a=(char)((unicode & 64) +128);
					b=(char)((unicode >> 6) +192);
					cur[curpos++]=b;
					cur[curpos++]=a;
				}
				else
				{
					cur[curpos++]=(char)unicode;
				}
				state=0;
			}
			break;
		}
		if(curpos>=maxpos)
		{
			error=6;
			goto _errorplace;
		}
	}
	if((state==-1)&&(cur==value))
	{
		if(!strcmp(name,"source"))
		{
			setsource=1;
		}
	}
	if(!setsource||!verifycite(line,reftype,basedoi))
	{
		error=7;
		goto _errorplace;
	}
_cleanup:
	if(tempname)
	{
		sprintf(citation,"%s%s",tempname,line);
	}
	else
	{
		error=8;
		goto _errorplace;
	}
_errorplace:
	return error;
}
static int do_gencite(const char *basedoi,char *citation,int reftype)
{
	char queryurl[8192];
	char line[4096];
	char doi_e[4096];
	HTTP res;
	int i,error;
	URLEncode(basedoi,strlen(basedoi),doi_e,4095);
	sprintf(queryurl,"%s%s",api_url,doi_e);
	res=hopen();
	if(get(queryurl,8080,0,res))
	{
		hclose(res);
		return -2;
	}
	i=hgets(line,512,res);
	if(i<12||strncmp(line,"HTTP/",5))
	{
		hclose(res);
		return -3;
	}
	if(line[9]!='2')
	{
		hclose(res);
		return -4;
	}
	if(skipresponseheader(res))
	{
		hclose(res);
		return -5;
	}
	error=cite_post_process(res,basedoi,citation,reftype);
	hclose(res);
	return error;
}
static int gencite(const char *doi,char *citation,int reftype)
{
	int pos;
	char doi_d[2048];
	*citation=0;
	pos=URLtryDecode(doi,strlen(doi),doi_d,2047,1);
	while(pos>0)
	{
		if(doi_d[pos-1]!=' ') break;
		pos--;
	}
	if(!pos) return -1;
	doi_d[pos]=0;
	for(pos=0;doi_d[pos]==' ';pos++);
	return do_gencite(doi_d+pos,citation,reftype);
}
const char *doi_temp="citedoi";
const char *pmid_temp="citepmid";
const char *isbn_temp="citeisbn";
static int isdoi(const char *title)
{
	int len=strlen(title);
	int count=0;
	int targetc=0;
	char target[2048];
	char ch;
	for(count=0;count<len;count++)
	{
		ch=title[count];
		if(ch=='\n'||ch=='\r'||ch==' '||ch=='_')
		{
		}
		else target[targetc++]=(ch>='A'&&ch<='Z')?ch+'a'-'A':ch;
	}
	target[targetc]=0;
	if(!strcmp(target,doi_temp)) return 1;
	if(!strcmp(target,pmid_temp)) return 2;
	/*
	if(!strcmp(target,isbn_temp)) return 3;
	*/
	return 0;
}
const char *citetype[3]={"DOI ","PMID ","ISBN "};
static int pagecheck(const char *pageid,const char *basetime,HTTP f)
{
	HTTP newtext;
	int error=0,status=0,todo=0;
	int i=0,brac=0,namepos=0,doipos=0;
	char ch=0,name[2048],name_e[4096],doi[2048],doi_e[4096],citation[65536],citation_e[65536*4];
	int hassomething[3]={0,0,0};
	int type=0;
	newtext=hopen();
	hputs("&text=",6,newtext);
	while(xmlpulltext(f,&ch)==XML_TEXT_CONTINUE)
	{
		switch(status)
		{
		case 0:
			if(ch=='{')
			{
				status=1;
				brac=1;
			}
			smartURLEncode(ch,newtext);
			break;
		case 1:
			if(ch=='{')
			{
				status=2;
				namepos=0;
			}
			else status=0;
			brac=0;
			smartURLEncode(ch,newtext);
			break;
		case 2:
			if(ch=='|')
			{
				name[namepos]=0;
				if(type=isdoi(name))
				{
					status=3;
					doipos=0;
				}
				else
				{
					i=URLEncode(name,namepos,name_e,4095);
					hputs(name_e,i,newtext);
					smartURLEncode('|',newtext);
					status=0;
				}
			}
			else if(ch=='{'||ch=='}'||ch=='['||ch==']'||namepos>=512)
			{
				name[namepos]=0;
				i=URLEncode(name,namepos,name_e,4095);
				hputs(name_e,i,newtext);
				smartURLEncode(ch,newtext);
				status=0;
			}
			else
			{
				name[namepos++]=ch;
			}
			break;
		case 3:
			if(ch=='}')
			{
				doi[doipos]=0;
				if(!gencite(doi,citation,type))
				{
					hassomething[type-1]=1;
					todo=1;
					i=URLEncode(citation,strlen(citation),citation_e,65536*4-2);
					hputs(citation_e,i,newtext);
				}
				else
				{
					i=URLEncode(name,namepos,name_e,4095);
					hputs(name_e,i,newtext);
					smartURLEncode('|',newtext);
					i=URLEncode(doi,doipos,doi_e,4095);
					hputs(doi_e,i,newtext);
				}
				smartURLEncode('}',newtext);
				status=0;
			}
			else if(doipos>512||ch=='{'||ch=='|')
			{
				i=URLEncode(name,namepos,name_e,4095);
				hputs(name_e,i,newtext);
				smartURLEncode('|',newtext);
				doi[doipos]=0;
				i=URLEncode(doi,doipos,doi_e,4095);
				hputs(doi_e,i,newtext);
				smartURLEncode(ch,newtext);
				if(ch=='{') status=1;
				else status=0;
			}
			else
			{
				doi[doipos++]=ch;
			}
			break;
		}
	}
	if(xmlpulltext(f,&ch)!=XML_TEXT_END) error=1;
	if(todo&&!status&&!error) 
	{
		struct neditargv point;
		char reason[64];
		point.newtext=newtext;
		point.id=pageid;
		point.time=basetime;
		strcpy(reason,"bot: expand ");
		for(i=0;i<3;i++)
		{
			if(hassomething[i]) strcat(reason,citetype[i]);
		}
		strcat(reason,"citations");
		smartedit(&point,reason,NULL);
	}
	hclose(newtext);
	return 0;
}
static int proceedchild(const char *ids)
{
	char url[4096];
	char buf[8192];
	char pageid[256];
	char timestamp[256];
	char contentmodel[64],contentformat[64];
	const char *ttm[]={"pageid"};
	const char *tmm[]={"timestamp"};
	const char *cmm[]={"contentmodel","contentformat"};
	char *ttv[1];
	char *tmv[1];
	char *cmv[2];
	int result;
	int status;
	HTTP h;
	ttv[0]=pageid;
	tmv[0]=timestamp;
	cmv[0]=contentmodel;
	cmv[1]=contentformat;
	if(!ids)
	{
		return -1;
	}
	sprintf(url,"/w/api.php?action=query&format=xml&prop=revisions&rvprop=content|timestamp&pageids=%s&rvslots=main",ids);
	h=hopen();
	if(get(url,8888,1,h))
	{
		hclose(h);
		return -2;
	}
	if(skipresponseheader(h))
	{
		hclose(h);
		return -3;
	}
	status=0;
	while(!heof(h))
	{
		result=xmlparsetag(h,buf);
		switch(status)
		{
		case 0:
			if(result==XML_HAS_VALUE&&!strcmp(buf,"page"))
			{
				if(xmlparsearg(h,1,ttm,ttv)==XML_HAS_VALUE)
				{
					if(atoi(pageid)) status=1;
				}
			}
			break;
		case 1:
			if(result==XML_HAS_VALUE&&!strcmp(buf,"rev"))
			{
				xmlparsearg(h,1,tmm,tmv);
				status=2;
			}
			break;
		case 2:
			if(result==XML_HAS_VALUE&&!strcmp(buf,"slot"))
			{
				xmlparsearg(h,2,cmm,cmv);
				if(!strcmp(contentmodel,"wikitext")&&!strcmp(contentformat,"text/x-wiki")) pagecheck(pageid,timestamp,h);
				status=0;
			}
			break;
		}
	}
	hclose(h);
	return 0;
}
static void threadfunc(void *c)
{
	int i=*(int *)c;
	int ext=0;
	char pageid[10][64];
	int count=0;
	char ids[4096];
	int result=0;
	struct problemlist *temp;
	while(!action) Sleep(1);
	while(1)
	{
		EnterCriticalSection(&hcs);
		for(count=0;count<5;count++)
		{
			if(pbl)
			{
				temp=pbl;
				pbl=pbl->next;
				sprintf(pageid[count],"%d",temp->pageid);
				s_free(temp);
			}
			else
			{
				ext=(count==0?1:2);
				count++;
				break;				
			}
		}
		count--;
		if(count>=0)
		{
			strcpy(ids,pageid[count]);
			count--;
			while(count>=0)
			{
				strcat(ids,"|");
				strcat(ids,pageid[count]);
				count--;
			}
		}
		LeaveCriticalSection(&hcs);
		if(ext==1) break;
		else
		{
			result=proceedchild(ids);
			if(ext==2) break;
		}
	}
	EnterCriticalSection(&tcs);
	threadnumber--;
	LeaveCriticalSection(&tcs);
	return ;
} 
static int threadini(int count)
{
	int i=0;
	int flag=0;
	threadnumber=0;
	for(i=0;i<count;i++)
	{
		threadc[i]=i;
		flag=_beginthread(threadfunc,0,(void *)(threadc+i));
		if(flag>0) threadnumber++;
	}
	return 0;
}
static int query(const char *target,const char *ns)
{
	HTTP f;
	char target_e[512],line[2048]={0},url[4096]={0},snd[4096]={0},id[512]={0},title[512]={0},sroffset[2048]={0},offseto[512]={0};
	char statusline[128]={0};
	int next=0,retry=0,pageid=0;
	struct problemlist *temp=0;
	char *ctm[]={"gsroffset"};
	char *ctv[1];
	char *idm[]={"pageid","title"};
	char *idv[2];
	ctv[0]=offseto;
	idv[0]=id;
	idv[1]=title;
	if(strlen(target)>128)
	{
		printf("Search string too long!\n");
		return -1;
	}
	URLEncode(target,strlen(target),target_e,511);
	sprintf(url,"/w/api.php?action=query&format=xml&generator=search&prop=info&gsrlimit=500&gsrnamespace=%s&gsrsearch=%s",ns,target_e);
	do
	{
		strcpy(snd,url);
		if(next)
		{
			strcat(snd,"&gsroffset=");
			strcat(snd,sroffset);
		}
		f=hopen();
		retry=0;
		do
		{
			if(get(snd,8888,1,f))
			{
				hclose(f);
				f=hopen();
			}
			else
			{
				hgets(statusline,127,f);
				if(strstr(statusline,"200")) break;
				else
				{
					hclose(f);
					f=hopen();
				}
			}
			retry++;
		}while(retry<20);
		if(retry==20)
		{
			hclose(f);
			return 1;
		}
		skipresponseheader(f);
		next=0;
		do
		{
			xmlparsetag(f,line);
			if(!next)
			{
				if(!strcmp(line,"continue"))
				{
					xmlparsearg(f,1,ctm,ctv);
					URLEncode(offseto,strlen(offseto),sroffset,990);
					next=1;
				}
			}
			if(!strcmp(line,"page"))
			{
				xmlparsearg(f,2,idm,idv);								
				if((pageid=atoi(id))>0)
				{
					temp=(struct problemlist *)s_malloc(sizeof(struct problemlist));
					temp->pageid=pageid;
					temp->next=pbl;
					pbl=temp;
				}
			}
		}while(!heof(f));
		hclose(f);
	}while(next);
	return 0;
}
static int allpagequery(const char *ns)
{
	HTTP f;
	char line[2048]={0},url[4096]={0},snd[4096]={0},id[512]={0},title[512]={0},sroffset[2048]={0},offseto[512]={0};
	char statusline[128];
	int next=0,retry=0,pageid=0;
	struct problemlist *temp=0;
	char *ctm[]={"apcontinue"};
	char *ctv[1];
	char *idm[]={"pageid","title"};
	char *idv[2];
	ctv[0]=offseto;
	idv[0]=id;
	idv[1]=title;
	sprintf(url,"/w/api.php?action=query&format=xml&list=allpages&apnamespace=%s&aplimit=5000&&apfilterredir=nonredirects",ns);
	do
 	{
		strcpy(snd,url);
		if(next)
		{
			strcat(snd,"&apcontinue=");
			strcat(snd,sroffset);
		}
		f=hopen();
		for(retry=0;retry<20;retry++)
		{
			if(get(snd,8888,1,f))
			{
				hclose(f);
				f=hopen();
			}
			else
			{
				hgets(statusline,127,f);
				if(strstr(statusline,"200")) break;
				else
				{
					hclose(f);
					f=hopen();
				}
			}
		}
		if(retry==20)
		{
			hclose(f);
			return 1;
		}
		skipresponseheader(f);
		next=0;
		do
		{
			xmlparsetag(f,line);
			if(!next)
			{
				if(!strcmp(line,"continue"))
				{
					xmlparsearg(f,1,ctm,ctv);
					URLEncode(offseto,strlen(offseto),sroffset,990);
					next=1;
				}
			}
			if(!strcmp(line,"p"))
			{
				xmlparsearg(f,2,idm,idv);
				if((pageid=atoi(id))>0)
				{
					temp=(struct problemlist *)s_malloc(sizeof(struct problemlist));
					temp->pageid=pageid;
					temp->next=pbl;
					pbl=temp;
				}
			}
		}while(!heof(f));
		hclose(f);
	}while(next);
	return 0;
}
#ifndef _DEBUG 
int main(int argc,char *argv[])
{
	int count=0;
	HANDLE tk_thread;
	if(parsearg(argc,argv))
	{
		printf("usage: -u username -p passwd [-T concurrency -s searchstring -a allpagequery -n namespace]\n");
		return -1;
	}
	InitializeSRWLock(&rwcs);
	InitializeCriticalSection(&tcs);
	InitializeCriticalSection(&hcs);
	InitializeCriticalSection(&fcs);
	buckini(20);
	if(login(username,passwd))
	{
		printf("Login error!\n");
		return -2;
	}
	hastoken=0;
	printf("Login complete.\n");
	fflush(stdout);
	ini_marks();
	tk_thread=(HANDLE)_beginthread(tokenmanage,0,0);
	if(doallpage)
	{
		allpagequery(ns);
	}
	else query(searchstring,ns);
	if(pbl==NULL)
	{
		printf("No page!\n");
		return -3;
	}
	printf("Query complete.\n");
	action=0;
	threadini(maxthread);
	action=1;
	while(1)
	{
		EnterCriticalSection(&hcs);
		if(pbl!=NULL)
		{
			LeaveCriticalSection(&hcs);
			Sleep(1000);
		}
		else
		{
			LeaveCriticalSection(&hcs);
			break;
		}
	}
	count=0;
	while(count<150)
	{
		count++;
		EnterCriticalSection(&tcs);
		if(threadnumber>0)
		{
			printf("Waiting for all threads to exit. Current thread number: %d\n",threadnumber);
			LeaveCriticalSection(&tcs);
		}
		else
		{
			LeaveCriticalSection(&tcs);
			break;
		}
		fflush(stdout);
		Sleep(1000);
	}
	if(!threadnumber)
	{
		printf("Cleanup..\n");
		DeleteCriticalSection(&tcs);
		DeleteCriticalSection(&hcs);
		AcquireSRWLockExclusive(&rwcs);
		hastoken=-1;
		ReleaseSRWLockExclusive(&rwcs);
		WaitForSingleObject(tk_thread,INFINITE);
		buckdestroy();
	}
	printf("---------------Ok done.---------------\n");
	fflush(stdout);
	return 0;
}
#else
int main(void)
{
	char citation[65536]={0};
	InitializeSRWLock(&rwcs);
	InitializeCriticalSection(&tcs);
	InitializeCriticalSection(&hcs);
	InitializeCriticalSection(&fcs);
	buckini(20);
	ini_marks();
	printf("%d\n",gencite("10.1080/00397918908054521",citation,1));
	printf("%s\n",citation);
	return 0;
}
/*
int main(int argc,char **argv)
{
	int count=0;
	if(parsearg(argc,argv))
	{
		printf("usage: -u username -p passwd [-T concurrency -s searchstring -a allpagequery -n namespace -i inputfile -o outputfile]\n");
		return -1;
	}
	InitializeSRWLock(&rwcs);
	InitializeCriticalSection(&tcs);
	InitializeCriticalSection(&hcs);
	buckini(20);
	if(login(username,passwd))
	{
		printf("Login error!\n");
		return -2;
	}
	hastoken=0;
	printf("Login complete.\n");
	fflush(stdout);
	_beginthread(tokenmanage,0,0);
	ini_marks();
	printf("ready!\n");
	proceedchild("5157328");
	return 0;
}*/
#endif