用戶:Antigng-bot/renameduser

#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"
#include "isip.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;
int threadnumber=0;
unsigned char action=0;
int loadfromfile=0;
struct hashlist *hl=NULL;
struct problemlist *pbl=NULL;
FILE *fp,*fp1;
const char *username=NULL;
const char *passwd=NULL;
const char *searchstring=NULL;
const char *ns=NULL;
int maxthread=256;
int doallpage=0;
int output=0;

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"
			);
	}
	if(code&0x80)
	{
		printf(
			"\tInvalid input file.\n"
			"\t\tCannot open the input file.\n"
			);
	}
	if(code&0x100)
	{
		printf(
			"\tInvalid output file.\n"
			"\t\tCannot open the output file.\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;
			case 'i':
				fp=fopen(argv[cur_arg+1],"r+");
				if(fp!=0) loadfromfile=1;
				else
				{
					err|=0x80;
				}
				cur_arg++;
				break;
			case 'o':
				fp1=fopen(argv[cur_arg+1],"w+");
				if(fp1!=0) output=1;
				else
				{
					err|=0x100;
				}
				cur_arg++;
				break;
			}
		}
	}
	if(!ns) ns="0";
	if(0x1+0x4+0x10==err) return 0;
	else
	{
		printf("Error code 0x%x:\n",err);
		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 *usernamelist;
struct hashlist *userrenamelist;
struct hashlist *dupuserlist;
struct hashlist *baduserlist;
static int userrenamed(const char *olduser,char **newuser)
{
	void *p;
	if(str_hashquery(baduserlist,olduser,&p)||str_hashquery(dupuserlist,olduser,&p)) return 0;
	return str_hashquery(userrenamelist,olduser,newuser);
}
	
static int usernameexist(const char *username)
{
	void *p;
	return str_hashquery(usernamelist,username,&p);
}
static int isip(const char *username)
{
	unsigned int username_u[1024];
	utf8tounicode(username,username_u);
	return regexIP(username_u);
}
const char *special;
const char *contrib_hans1,*contrib_hant1;
const char *contrib_hans2,*contrib_hant2;
const char *contrib_hans3,*contrib_hant3;
const char *delcontrib_hans;
const char *logs_hans;
const char *logs_hant;
const char *ul_hans1;
const char *ca_hans;
const char *ur_hans;
const char *af_hans;
const char *http_mark1,*http_mark2;
const char *domain_mark1,*domain_mark2;
const char *mail_hans,*mail_hant;
const char *upload_hans1,*upload_hant1;
const char *upload_hans2,*upload_hant2;
const char *upload_hant3;
struct hashlist *logtype;
struct hashlist *urltoken;
int urltokentype[4]={0,1,2,3};
static void ini_marks()
{
	special=G2U("特殊:");
	contrib_hans1=G2U("用户贡献/");
	contrib_hant1=G2U("用戶貢獻/");
	contrib_hans2=G2U("使用者贡献/");
	contrib_hant2=G2U("使用者貢獻/");
	contrib_hans3=G2U("贡献/");
	contrib_hant3=G2U("貢獻/");
	delcontrib_hans=G2U("删除的贡献/");
	logs_hans=G2U("日志/");
	logs_hant=G2U("日誌/");
	ul_hans1=G2U("用户列表/");
	ca_hans=G2U("中央认证/");
	ur_hans=G2U("用户权限/");
	af_hans=G2U("滥用日志/");
	mail_hans=G2U("电邮联系/");
	mail_hant=G2U("電郵聯絡/");
	upload_hans1=G2U("文件列表/");
	upload_hant1=G2U("檔案列表/");
	upload_hans2=G2U("上传/");
	upload_hant2=G2U("上載/");
	upload_hant3=G2U("上傳/");
	logtype=hashini();
	str_hashadd(logtype,"timedmediahandler",NULL);
	str_hashadd(logtype,"upload",NULL);
	str_hashadd(logtype,"protect",NULL);
	str_hashadd(logtype,"gblblock",NULL);
	str_hashadd(logtype,"gblrights",NULL);
	str_hashadd(logtype,"globalauth",NULL);
	str_hashadd(logtype,"gblrename",NULL);
	str_hashadd(logtype,"contentmodel",NULL);
	str_hashadd(logtype,"delete",NULL);
	str_hashadd(logtype,"merge",NULL);
	str_hashadd(logtype,"spamblacklist",NULL);
	str_hashadd(logtype,"massmessage",NULL);
	str_hashadd(logtype,"import",NULL);
	str_hashadd(logtype,"block",NULL);
	str_hashadd(logtype,"patrol",NULL);
	str_hashadd(logtype,"thanks",NULL);
	str_hashadd(logtype,"tag",NULL);
	str_hashadd(logtype,"managetags",NULL);
	str_hashadd(logtype,"titleblacklist",NULL);
	str_hashadd(logtype,"abusefilter",NULL);
	str_hashadd(logtype,"newusers",NULL);
	str_hashadd(logtype,"usermerge",NULL);
	str_hashadd(logtype,"renameuser",NULL);
	str_hashadd(logtype,"rights",NULL);
	str_hashadd(logtype,"move",NULL);
	str_hashadd(logtype,"create",NULL);
	http_mark1="http";
	http_mark2="HTTP";
	domain_mark1="://zh.wikipedia.org/";
	domain_mark2="://ZH.WIKIPEDIA.ORG/";
	urltoken=hashini();
	str_hashadd(urltoken,"title",urltokentype);
	str_hashadd(urltoken,"user",urltokentype+1);
	str_hashadd(urltoken,"target",urltokentype+2);
	str_hashadd(urltoken,"wpSearchUser",urltokentype+3);
	return ;
}
static int strncasecmp(const char *a,const char *b,const unsigned int k)
{
	char c1=0,c2=0;
	register unsigned int count=0;
	do
	{
		c1=a[count];
		c1=((c1>='A')&&(c1<='Z'))?c1+'a'-'A':c1;
		c2=b[count];
		c2=((c2>='A')&&(c2<='Z'))?c2+'a'-'A':c2;
		if(c1>c2) return 1;
		if(c1<c2) return -1;
		count++;
	}while(c1&&c2&&(count<k));
	return 0;
}
static int checkusercontrib(const char *ori_link,char *fixedlink)
{
	int linkpos=0,baselinkpos=0;
	int todo=0;
	int log=0;
	char username[1024],link[2048];
	char *newuser;
	int usernamepos=0;
	URLtryDecode(ori_link,strlen(ori_link),link,2046,0);
	if(!strncasecmp(link,"Special:",8))
	{
		linkpos=8;
	}
	else if(!strncmp(link,special,7))
	{
		linkpos=7;
	}
	else goto nothingtodo;
	if(!strncasecmp((link+linkpos),"Contributions/",14))
	{
		linkpos+=14;
	}
	else if(!strncasecmp((link+linkpos),"Contribs/",9))
	{
		linkpos+=9;
	}
	else if(!strncmp((link+linkpos),contrib_hans1,13)||!strncmp((link+linkpos),contrib_hant1,13))
	{
		linkpos+=13;
	}
	else if(!strncmp((link+linkpos),contrib_hans2,16)||!strncmp((link+linkpos),contrib_hant2,16))
	{
		linkpos+=16;
	}
	else if(!strncmp((link+linkpos),contrib_hans3,7)||!strncmp((link+linkpos),contrib_hant3,7))
	{
		linkpos+=7;
	}
	else if(!strncasecmp((link+linkpos),"Filelist/",9))
	{
		linkpos+=9;
	}
	else if(!strncasecmp((link+linkpos),"Uploads/",8))
	{
		linkpos+=8;
	}
	else if(!strncmp((link+linkpos),upload_hans1,13)||!strncmp((link+linkpos),upload_hant1,13))
	{
		linkpos+=13;
	}
	else if(!strncmp((link+linkpos),upload_hans2,7)||!strncmp((link+linkpos),upload_hant2,7)||!strncmp((link+linkpos),upload_hant3,7))
	{
		linkpos+=7;
	}
	else if(!strncasecmp((link+linkpos),"Email/",6))
	{
		linkpos+=6;
	}
	else if(!strncasecmp((link+linkpos),"EmailUser/",10))
	{
		linkpos+=10;
	}
	else if(!strncmp((link+linkpos),mail_hans,13)||!strncmp((link+linkpos),mail_hant,13))
	{
		linkpos+=13;
	}
	else if(!strncasecmp((link+linkpos),"DeletedContributions/",21))
	{
		linkpos+=21;
	}
	else if(!strncmp((link+linkpos),delcontrib_hans,16))
	{
		linkpos+=16;
	}
	else if(!strncasecmp((link+linkpos),"Log/",4))
	{
		linkpos+=4;
		log=1;
	}
	else if(!strncasecmp((link+linkpos),"Logs/",5))
	{
		linkpos+=5;
		log=1;
	}
	else if(!strncmp((link+linkpos),logs_hans,7)||!strncmp((link+linkpos),logs_hant,7))
	{
		linkpos+=7;
		log=1;
	}
	/*
	else if(!strncasecmp((link+linkpos),"Listusers/",10))
	{
		linkpos+=10;
	}
	else if(!strncmp((link+linkpos),ul_hans1,13))
	{
		linkpos+=13;
	}*/
	/*
	else if(!strncasecmp((link+linkpos),"CentralAuth/",12))
	{
		linkpos+=12;
	}
	else if(!strncmp((link+linkpos),ca_hans,13))
	{
		linkpos+=13;
	}*/
	else if(!strncasecmp((link+linkpos),"UserRights/",11))
	{
		linkpos+=11;
	}
	else if(!strncmp((link+linkpos),ur_hans,13))
	{
		linkpos+=13;
	}
	else goto nothingtodo;
	if(log)
	{
		int count;
		int type=0;
		for(count=linkpos;link[count];count++)
		{
			if(link[count]=='{'||link[count]=='}'
				||link[count]=='<'||link[count]=='>'
				||link[count]=='\\'
				||link[count]=='#'
				||link[count]=='$'
				||link[count]=='['||link[count]==']') goto nothingtodo;
			if(link[count]=='/')
			{
				type=1;
				break;
			}
		}
		if(type)
		{
			baselinkpos=linkpos=count+1;
			while(link[linkpos]==' ') linkpos++;
			while(link[linkpos])
			{
				if(link[linkpos]=='{'||link[linkpos]=='}'
					||link[linkpos]=='<'||link[linkpos]=='>'
					||link[linkpos]=='\\'
					||link[linkpos]=='#'
					||link[linkpos]=='$'
					||link[linkpos]=='['||link[linkpos]==']') goto nothingtodo;
				username[usernamepos]=(link[linkpos]=='_')?' ':link[linkpos];
				usernamepos++;
				linkpos++;
			}
			if(usernamepos==0) goto nothingtodo;
			username[usernamepos]=0;
		}
		else
		{
			void *p;
			baselinkpos=linkpos;
			while(link[linkpos]==' ') linkpos++;
			while(link[linkpos])
			{
				username[usernamepos]=(link[linkpos]=='_')?' ':link[linkpos];
				usernamepos++;
				linkpos++;
			}
			if(usernamepos==0) goto nothingtodo;
			username[usernamepos]=0;
			if(str_hashquery(logtype,username,&p)) goto nothingtodo;
		}
	}
	else
	{
		baselinkpos=linkpos;
		while(link[linkpos]==' ') linkpos++;
		while(link[linkpos])
		{
			if(link[linkpos]=='{'||link[linkpos]=='}'
				||link[linkpos]=='<'||link[linkpos]=='>'
				||link[linkpos]=='\\'
				||link[linkpos]=='#'
				||link[linkpos]=='$'
				||link[linkpos]=='['||link[linkpos]==']') goto nothingtodo;
			username[usernamepos]=(link[linkpos]=='_')?' ':link[linkpos];
			usernamepos++;
			linkpos++;
		}
		if(usernamepos==0) goto nothingtodo;
		username[usernamepos]=0;
	}
	while(usernamepos>0)
	{
		if(username[usernamepos-1]==' ') usernamepos--;
		else break;
	}
	username[usernamepos]=0;
	if(!strcmp(username,"newbies")) goto nothingtodo;
	if(isip(username)) goto nothingtodo;	
	if(username[0]>='a'&&username[0]<='z') username[0]-='a'-'A';
	if(usernameexist(username)) goto nothingtodo;
	if(!userrenamed(username,&newuser))
	{
		goto nothingtodo;
	}
	todo=1;
	strncpy(fixedlink,link,baselinkpos);
	fixedlink[baselinkpos]=0;
	strcat(fixedlink,newuser);
nothingtodo:
	return todo;
}
static void format_url(char *url)
{
	register int i;
	for(i=0;url[i];i++)
	{
		if(url[i]==' ') url[i]='_';
	}
	return;
}
static void format_username(char *username)
{
	register int i;
	if((*username>='a')&&(*username<='z')) *username-='a'-'A';
	for(i=0;username[i];i++)
	{
		if(username[i]=='_') username[i]=' ';
	}
	return;
}

struct _str
{
	const char *s;
	unsigned int len;
};
static int url_checkusercontrib(const char *url,char *fixed_url)
{
	int i=0;
	int urlpos=0;
	int baseurlpos=0;
	char name[1024];
	char value_ori[8192],value_dec[8192],*fixed_value,fixed[8192];
	char ch;
	int namepos=0;
	int valuepos=0,value_dec_len=0;
	int exp=0,ext=0;
	int status=0;
	int log=0;
	int todo=0;
	struct _str *p;
	struct _str var[10]={0};
	void *q;
	if(!strncmp(url,"wiki/",5))
	{
		urlpos=5;
		exp=0;
	}
	else if(!strncmp(url,"w/index.php?",12))
	{
		urlpos=12;
		exp=1;
	}
	else return 0;
	if(!exp)
	{
		int query=0;
		ch=url[urlpos+valuepos];
		while(ch)
		{
			if(ch=='?')
			{
				query=1;
				break;
			}
			else if(ch=='#'||ch=='|') return 0;
			value_ori[valuepos]=ch;
			valuepos++;
			ch=url[urlpos+valuepos];
		}
		if(valuepos==0) return 0;
		value_ori[valuepos]=0;
		if(!query)
		{
			URLtryDecode(value_ori,strlen(value_ori),value_dec,2047,1);
			if(checkusercontrib(value_dec,fixed))
			{
				strncpy(fixed_url,url,urlpos);
				fixed_url[urlpos]=0;
				strcat(fixed_url,fixed);
				format_url(fixed_url);
				return 1;
			}
			else return 0;
		}
	}
	if(!exp)
	{
		var[0].s=url+urlpos;
		var[0].len=valuepos;
		urlpos+=valuepos+1;
		valuepos=0;
	}
	ch=url[urlpos];
	while(1)
	{
		switch(status)
		{
		case 0:
			if(ch=='=')
			{
				name[namepos]=0;
				baseurlpos=urlpos+1;
				valuepos=0;
				status=1;
			}
			else if(ch=='&'||ch==0)
			{
				namepos=0;
			}
			else
			{
				name[namepos]=ch;
				namepos++;
			}
			break;
		case 1:
			if(ch=='&'||ch==0)
			{
				int *n;
				while(namepos>0)
				{
					if(name[namepos-1]==' ') namepos--;
					else break;
				}
				name[namepos]=0;
				i=0;
				while(name[i]==' ') i++;
				if(str_hashquery(urltoken,name+i,&n))
				{
					if(var[*n].s) goto nothingtodo;
					var[*n].len=valuepos;
					var[*n].s=url+baseurlpos;
				}
				valuepos=0;
				namepos=0;
				status=0;
			}
			else
			{
				valuepos++;
			}
			break;
		}
		if(!ch) break;
		ch=url[++urlpos];
	}
	if(!var[0].s) goto nothingtodo;
	p=var;
	strncpy(value_ori,p->s,p->len);
	value_ori[p->len]=0;
	valuepos=0;
	value_dec_len=URLtryDecode(value_ori,p->len,value_dec,2047,1);
	if(!strncasecmp(value_dec,"Special:",8))
	{
		valuepos=8;
	}
	else if(!strncmp(value_dec,special,7))
	{
		valuepos=7;
	}
	else goto nothingtodo;
	if(!strncasecmp(value_dec+valuepos,"Log",3))
	{
		valuepos+=3;
		if(valuepos==value_dec_len)
		{
			ext=2;
		}
		else if(value_dec_len==valuepos+1)
		{
			if(value_dec[valuepos]=='s'||value_dec[valuepos]=='S')
			{
				ext=2;
			}
			else goto nothingtodo;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else if((value_dec[valuepos]=='S'||value_dec[valuepos]=='s')&&value_dec[valuepos+1]=='/')
		{
			valuepos+=2;
			ext=1;
		}
		else goto nothingtodo;
		log=1;
	}
	else if(!strncmp(value_dec+valuepos,logs_hans,6)||!strncmp(value_dec+valuepos,logs_hant,6))
	{
		valuepos+=6;
		if(valuepos==value_dec_len)
		{
			ext=2;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
		log=1;
	}
	else if(!strncasecmp(value_dec+valuepos,"Contributions",13))
	{
		valuepos+=13;
		if(valuepos==value_dec_len)
		{
			ext=3;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncasecmp(value_dec+valuepos,"Contribs",8))
	{
		valuepos+=8;
		if(valuepos==value_dec_len)
		{
			ext=3;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncasecmp(value_dec+valuepos,"Filelist",8))
	{
		valuepos+=8;
		if(valuepos==value_dec_len)
		{
			ext=2;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncasecmp(value_dec+valuepos,"Uploads",7))
	{
		valuepos+=7;
		if(valuepos==value_dec_len)
		{
			ext=2;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncmp(value_dec+valuepos,upload_hans1,12)||!strncmp(value_dec+valuepos,upload_hant1,12))
	{
		valuepos+=12;
		if(valuepos==value_dec_len)
		{
			ext=2;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncmp(value_dec+valuepos,upload_hans2,6)||!strncmp(value_dec+valuepos,upload_hant2,6)||!strncmp(value_dec+valuepos,upload_hant3,6))
	{
		valuepos+=6;
		if(valuepos==value_dec_len)
		{
			ext=2;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncasecmp(value_dec+valuepos,"EmailUser",9))
	{
		valuepos+=9;
		if(valuepos==value_dec_len)
		{
			ext=3;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncasecmp(value_dec+valuepos,"Email",5))
	{
		valuepos+=5;
		if(valuepos==value_dec_len)
		{
			ext=3;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncmp(value_dec+valuepos,mail_hans,12)||!strncmp((value_dec+valuepos),mail_hant,12))
	{
		valuepos+=12;
		if(valuepos==value_dec_len)
		{
			ext=3;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncmp(value_dec+valuepos,contrib_hans3,6)||!strncmp(value_dec+valuepos,contrib_hant3,6))
	{
		valuepos+=6;
		if(valuepos==value_dec_len)
		{
			ext=3;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncmp(value_dec+valuepos,contrib_hans1,12)||!strncmp(value_dec+valuepos,contrib_hant1,12))
	{
		valuepos+=12;
		if(valuepos==value_dec_len)
		{
			ext=3;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncmp(value_dec+valuepos,contrib_hans2,15)
		||!strncmp(value_dec+valuepos,contrib_hant2,15)
		||!strncmp(value_dec+valuepos,delcontrib_hans,15))
	{
		valuepos+=15;
		if(valuepos==value_dec_len)
		{
			ext=3;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncasecmp(value_dec+valuepos,"DeletedContributions",20))
	{
		valuepos+=20;
		if(valuepos==value_dec_len)
		{
			ext=3;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncasecmp(value_dec+valuepos,"UserRights",10))
	{
		valuepos+=10;
		if(valuepos==value_dec_len)
		{
			ext=2;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncasecmp(value_dec+valuepos,ur_hans,12))
	{
		valuepos+=12;
		if(valuepos==value_dec_len)
		{
			ext=2;
		}
		else if(value_dec[valuepos]=='/')
		{
			valuepos++;
			ext=1;
		}
		else goto nothingtodo;
	}
	else if(!strncasecmp(value_dec+valuepos,"Abuselog",8))
	{
		valuepos+=8;
		if(valuepos==value_dec_len)
		{
			ext=4;
		}
		else goto nothingtodo;
	}
	else if(!strncasecmp(value_dec+valuepos,af_hans,12))
	{
		valuepos+=12;
		if(valuepos==value_dec_len)
		{
			ext=4;
		}
		else goto nothingtodo;
	}
	else goto nothingtodo;
	if(log)
	{
		for(i=valuepos;value_dec[i];i++)
		{
			if(value_dec[i]=='/')
			{
				log=0;
				break;
			}
		}
		if(!log) valuepos=i+1;
	}
	switch(ext)
	{
	case 1:
		baseurlpos=p->s-url;
		strncpy(fixed_url,url,baseurlpos);
		fixed_url[baseurlpos]=0;
		strncat(fixed_url,value_dec,valuepos);
		fixed_url[baseurlpos+valuepos]=0;
		while(value_dec[valuepos]==' ') valuepos++;
		i=value_dec_len;
		while(i>0)
		{
			if(value_dec[i-1]==' ') i--;
			else break;
		}
		value_dec[i]=0;
		if(i<=valuepos) goto nothingtodo;
		if(!log||!str_hashquery(logtype,value_dec+valuepos,&q))
		{
			if(isip(value_dec+valuepos)) goto nothingtodo;
			if(!strcmp(value_dec+valuepos,"newbies")) goto nothingtodo;
			format_username(value_dec+valuepos);
			if(usernameexist(value_dec+valuepos)) goto nothingtodo;
			if(!userrenamed(value_dec+valuepos,&fixed_value)) goto nothingtodo;
			else
			{
				goto cleanup;
			}
			break;
		}
	case 2:
		p=var+1;
		if(!p->s) goto nothingtodo;
		break;
	case 3:
		p=var+2;
		if(!p->s) goto nothingtodo;
		break;
	case 4:
		p=var+3;
		if(!p->s) goto nothingtodo;
		break;
	}
	baseurlpos=p->s-url;
	strcpy(value_ori,p->s);
	value_dec_len=URLtryDecode(value_ori,p->len,value_dec,2047,1);
	while(value_dec_len>0)
	{
		if(value_dec[value_dec_len-1]==' ') value_dec_len--;
		else break;
	}
	valuepos=0;
	while(value_dec[valuepos]==' ') valuepos++;
	if(valuepos>=value_dec_len) goto nothingtodo;
	value_dec[value_dec_len]=0;
	if(isip(value_dec+i)) goto nothingtodo;
	if(!strcmp(value_dec+valuepos,"newbies")) goto nothingtodo;
	format_username(value_dec+valuepos);
	if(usernameexist(value_dec+valuepos)) goto nothingtodo;
	if(!userrenamed(value_dec+valuepos,&fixed_value)) goto nothingtodo;
	strncpy(fixed_url,url,baseurlpos);
	fixed_url[baseurlpos]=0;
cleanup:
	strcat(fixed_url,fixed_value);
	strcat(fixed_url,p->s+p->len);
	format_url(fixed_url);
	todo=1;
nothingtodo:
	return todo;
}
static int pagecheck(const char *pageid,const char *basetime,HTTP f)
{
	HTTP newtext;
	int status=0,error=0,todo=0;
	int i=0,namepos=0,displaypos=0;
	int protpos=0;
	unsigned int domainpos=0;
	int urlpos=0;
	char ch=0,name[2048],fixed_name[2048],name_e[4096],display[2048],display_e[4096];
	char url[2048],url_e[8192],fixed_url[2048];
	newtext=hopen();
	hputs("&text=",6,newtext);
	while(xmlpulltext(f,&ch)==XML_TEXT_CONTINUE)
	{
		switch(status)
		{
		case 0:
			if(ch=='[')
			{
				status=1;
			}
			smartURLEncode(ch,newtext);
			break;
		case 1:
			if(ch=='[')
			{
				status=2;
				namepos=0;
			}
			else if(ch=='h'||ch=='H')
			{
				status=4;
				protpos=1;
			}
			else if(ch=='/')
			{
				status=6;
				domainpos=2;
			}
			else status=0;
			smartURLEncode(ch,newtext);
			break;
		case 2:
			if(ch=='|')
			{
				name[namepos]=0;
				status=3;
				displaypos=0;
			}
			else if(ch==']')
			{
				name[namepos]=0;
				if(checkusercontrib(name,fixed_name))
				{
					todo=1;
					i=URLEncode(fixed_name,strlen(fixed_name),name_e,2048);
				}
				else
				{
					i=URLEncode(name,namepos,name_e,4095);
				}
				hputs(name_e,i,newtext);
				smartURLEncode(']',newtext);
				status=0;
			}
			else if((namepos>512)||ch=='{'||ch=='}'||ch=='<'||ch=='>'||ch=='['||ch=='\n'||ch=='\r')
			{
				name[namepos]=0;
				i=URLEncode(name,namepos,name_e,4095);
				hputs(name_e,i,newtext);
				smartURLEncode(ch,newtext);
				if(ch=='[')
				{
					status=1;
				}
				else status=0;
			}
			else
			{
				name[namepos++]=ch;
			}
			break;
		case 3:
			if(ch==']')
			{
				display[displaypos]=0;
				if(checkusercontrib(name,fixed_name))
				{
					todo=1;
					i=URLEncode(fixed_name,strlen(fixed_name),name_e,2048);
				}
				else
				{
					i=URLEncode(name,namepos,name_e,2048);
				}
				hputs(name_e,i,newtext);
				smartURLEncode('|',newtext);
				i=URLEncode(display,displaypos,display_e,2048);
				hputs(display_e,i,newtext);
				smartURLEncode(']',newtext);
				status=0;
			}
			else if(ch=='[')
			{
				display[displaypos]=0;
				if(checkusercontrib(name,fixed_name))
				{
					todo=1;
					i=URLEncode(fixed_name,strlen(fixed_name),name_e,2048);
				}
				else
				{
					i=URLEncode(name,namepos,name_e,2048);
				}
				hputs(name_e,i,newtext);
				smartURLEncode('|',newtext);
				i=URLEncode(display,displaypos,display_e,2048);
				hputs(display_e,i,newtext);
				status=1;
				smartURLEncode(ch,newtext);
			}
			else if(displaypos>512)
			{
				display[displaypos]=0;
				if(checkusercontrib(name,fixed_name))
				{
					todo=1;
					i=URLEncode(fixed_name,strlen(fixed_name),name_e,2048);
				}
				else
				{
					i=URLEncode(name,namepos,name_e,2048);
				}
				hputs(name_e,i,newtext);
				smartURLEncode('|',newtext);
				i=URLEncode(display,displaypos,display_e,2048);
				hputs(display_e,i,newtext);
				status=0;
				smartURLEncode(ch,newtext);
			}
			else
			{
				display[displaypos++]=ch;
			}
			break;
		case 4:
			if((ch==http_mark1[protpos])||(ch==http_mark2[protpos]))
			{
				protpos++;
			}
			else if(ch=='[')
			{
				status=1;
				protpos=0;
			}
			else
			{
				status=0;
				protpos=0;
			}
			if(protpos==4)
			{
				status=5;
				protpos=0;
			}
			smartURLEncode(ch,newtext);
			break;
		case 5:
			if(ch==':')
			{
				status=6;
				domainpos=1;
			}
			else if(ch=='s'||ch=='S')
			{
				status=6;
				domainpos=0;
			}
			else if(ch=='[')
			{
				status=1;
			}
			else status=0;
			smartURLEncode(ch,newtext);
			break;
		case 6:
			if(ch==domain_mark1[domainpos]||ch==domain_mark2[domainpos])
			{
				domainpos++;
			}
			else if(ch=='[')
			{
				status=1;
				domainpos=0;
			}
			else
			{
				status=0;
				domainpos=0;
			}
			if(domainpos==strlen(domain_mark1))
			{
				status=7;
				domainpos=0;
			}
			smartURLEncode(ch,newtext);
			break;
		case 7:
			if(ch==']'||ch==' ')
			{
				url[urlpos]=0;
				if(url_checkusercontrib(url,fixed_url))
				{
					i=URLEncode(fixed_url,strlen(fixed_url),url_e,8190);
					todo=1;
				}
				else
				{
					i=URLEncode(url,urlpos,url_e,8190);
				}
				hputs(url_e,i,newtext);
				urlpos=0;
				status=0;
				smartURLEncode(ch,newtext);
			}
			else if(ch=='|'||ch=='{'||ch=='}'||ch=='['||ch=='\n'||ch=='\r'||urlpos>1024)
			{
				url[urlpos]=0;
				i=URLEncode(url,urlpos,url_e,8190);
				hputs(url_e,i,newtext);
				urlpos=0;
				if(ch=='[')
				{
					status=1;
				}
				else status=0;
				smartURLEncode(ch,newtext);
			}
			else
			{
				url[urlpos++]=ch;
			}
			break;
		}
	}
	if(xmlpulltext(f,&ch)!=XML_TEXT_END) error=1;
	if(todo&&!status&&!error)
	{
		struct neditargv point;
		point.newtext=newtext;
		point.id=pageid;
		point.time=basetime;
		smartedit(&point,"bot: cleanup after user rename",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;
	}
	hgets(buf,4096,h);
	if(!strstr(buf," 200"))
	{
		hclose(h);
		return -3;
	}
	if(skipresponseheader(h))
	{
		hclose(h);
		return -3;
	}
	status=0;
	while(!heof(h))
	{
		result=xmlparsetag(h,buf);
		if(result==XML_HAS_VALUE)
		{
			switch(status)
			{
			case 0:
				if(!strcmp(buf,"page")&&(xmlparsearg(h,1,ttm,ttv)==XML_HAS_VALUE))
				{
					if(atoi(pageid)>0) status=1;
				}
				break;
			case 1:
				if(!strcmp(buf,"rev"))
				{
					if(xmlparsearg(h,1,tmm,tmv)!=XML_HAS_VALUE)
					{
						status=3;
						goto _cleanup;
					}
					status=2;
				}
				else goto _cleanup;
				break;
			case 2:
				if(!strcmp(buf,"slot"))
				{
					if(xmlparsearg(h,2,cmm,cmv)!=XML_HAS_VALUE)
					{
						status=3;
						goto _cleanup;
					}
					if(!strcmp(contentmodel,"wikitext")&&!strcmp(contentformat,"text/x-wiki"))
					{
						pagecheck(pageid,timestamp,h);
					}
					status=0;
				}
				else goto _cleanup;
				break;
			}
		}
		else if(result==XML_PARSE_ERROR)
		{
			status=3;
			goto _cleanup;
		}
	}
_cleanup:
	hclose(h);
	return status?-4:0;
}
static void threadfunc(void *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<10;count++)
		{
			if(pbl)
			{
				temp=pbl;
				pbl=pbl->next;
				sprintf(pageid[count],"%d",temp->pageid);
				s_free(temp);
			}
			else
			{
				ext=2-(!count);
				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,2047);
					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",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,2047);
					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;
}
static int loadusernametable()
{
	HTTP f;
	char line[2048]={0},url[4096]={0},snd[4096]={0},id[512]={0},name[512]={0},sroffset[2048]={0},offseto[512]={0};
	char statusline[128];
	int status=0,next=0,retry=0,count=0;
	char *ctm[]={"aufrom"};
	char *ctv[1];
	char *idm[]={"userid","name"};
	char *idv[2];
	ctv[0]=offseto;
	idv[0]=id;
	idv[1]=name;
	usernamelist=hashini();
	sprintf(url,"/w/api.php?action=query&list=allusers&format=xml&aulimit=5000");
	do
	{
		strcpy(snd,url);
		if(next)
		{
			strcat(snd,"&aufrom=");
			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"))
				{
					hclose(f);
					f=hopen();
				}
				else
				{
					skipresponseheader(f);
					next=0;count=0;
					do
					{
						if(xmlparsetag(f,line)==XML_PARSE_ERROR) break;
						if(!next)
						{
							if(!strcmp(line,"continue"))
							{
								xmlparsearg(f,1,ctm,ctv);
								URLEncode(offseto,strlen(offseto),sroffset,2047);
								next=1;
							}
						}
						if(!strcmp(line,"allusers"))
						{
							status=1;
						}
						if(!strcmp(line,"u"))
						{
							if(xmlparsearg(f,2,idm,idv)!=XML_HAS_VALUE) break;
							count++;
							if(!strstr(name,"~zhwiki"))
							{
								void *p;
								if(!str_hashquery(usernamelist,name,&p))
								{
									if(output)
									{
										fprintf(fp1,"%s\n",name);
										fflush(fp1);
									}
									str_hashadd(usernamelist,name,0);
								}
							}
						}
					}while(!heof(f));
					hclose(f);
					if(status&&((!next)||(count==5000))) break;
					else
					{
						f=hopen();
					}
				}
			}
		}
		if(retry==20)
		{
			hclose(f);
			return 1;
		}
	}while(next);
	if(output) fclose(fp1);
	return !status;
}
static int loaduserfromlocalfile()
{
	char line[1024];
	int length;
	usernamelist=hashini();
	while(!feof(fp))
	{
		void *p;
		fgets(line,1023,fp);
		length=strlen(line);
		if(line[length-1]=='\n')
		{
			line[length-1]=0;
			length--;
		}
		if(!str_hashquery(usernamelist,line,&p))
		{
			str_hashadd(usernamelist,line,NULL);
		}
	}
	fclose(fp);
	return 0;
}
static int loadrenamelog()
{
	HTTP f;
	void *p;
	char line[2048]={0},url[4096]={0},snd[4096]={0},olduser[512]={0},newuser[512]={0},sroffset[2048]={0},offseto[512]={0};
	char statusline[128];
	int next=0,retry=0,bad=0;
	char *ctm[]={"lecontinue"};
	char *ctv[1];
	char *idm[]={"olduser","newuser"};
	char *idv[2];
	ctv[0]=offseto;
	idv[0]=olduser;
	idv[1]=newuser;
	userrenamelist=hashini();
	dupuserlist=hashini();
	baduserlist=hashini();
	sprintf(url,"/w/api.php?action=query&list=logevents&format=xml&leprop=details&letype=renameuser&lelimit=5000");
	do
	{
		strcpy(snd,url);
		if(next)
		{
			strcat(snd,"&lecontinue=");
			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,2047);
					next=1;
				}
			}
			if(!strcmp(line,"params"))
			{
				xmlparsearg(f,2,idm,idv);
				bad=0;
				if(!olduser[0]||!newuser[0]) continue;
				else if(strstr(olduser,"~zhwiki")||strstr(newuser,"~zhwiki"))
				{
					bad=2;
				}
				else if(str_hashquery(baduserlist,newuser,&p))
				{
					bad=2;
				}
				else if(str_hashquery(userrenamelist,newuser,&p))
				{
					void *q;
					if(str_hashquery(usernamelist,olduser,&q))
					{
						bad=1;
					}
					else
					{
						if(str_hashquery(userrenamelist,olduser,&q))
						{
							if(strcmp(q,p)) bad=1;
							s_free(q);
						}
						q=s_calloc(strlen(p)+3,1);
						strcpy(q,p);
						str_hashadd(userrenamelist,olduser,q);
					}
				}
				else if(str_hashquery(usernamelist,newuser,&p))
				{
					void *q;
					if(str_hashquery(usernamelist,olduser,&q))
					{
						bad=1;
					}
					else
					{
						if(str_hashquery(userrenamelist,olduser,&q))
						{
							if(strcmp(q,newuser)) bad=1;
							s_free(q);
						}
						p=s_calloc(strlen(newuser)+3,1);
						strcpy(p,newuser);
						str_hashadd(userrenamelist,olduser,p);
					}
				}
				else bad=2;
				switch(bad)
				{
				case 0:
					break;
				case 1:
					if(!str_hashquery(dupuserlist,olduser,&p))
					{
						str_hashadd(dupuserlist,olduser,NULL);
					}
					break;
				case 2:
					if(!str_hashquery(baduserlist,olduser,&p))
					{
						str_hashadd(baduserlist,olduser,NULL);
					}
					break;
				}
			}
		}while(!heof(f));
		hclose(f);
	}while(next);
	return 0;
}
#ifdef _DEBUG
#include <crtdbg.h>
void dumpfunc(const char *name,void *p,void *q)
{
	fprintf((FILE *)q,"%s\n",name);
	return;
}
void dumpbadlog()
{
	FILE *fp=fopen("debug.txt","w+");
	str_hashdump(baduserlist,dumpfunc,fp);
	fclose(fp);
	return;
}
void dumpduplog()
{
	FILE *fp=fopen("dup.txt","w+");
	str_hashdump(dupuserlist,dumpfunc,fp);
	fclose(fp);
	return;
}
void dumprnfunc(const char *name,void *p,void *q)
{
	fprintf((FILE *)q,"%s -> %s\n",name,(char *)p);
	return;
}
void dumprenamelog()
{
	FILE *fp=fopen("rename.txt","w+");
	str_hashdump(userrenamelist,dumprnfunc,fp);
	fclose(fp);
	return;
}
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);
	if(loadfromfile)
	{
		loaduserfromlocalfile();
	}
	else loadusernametable();
	loadrenamelog();
	dumprenamelog();
	dumpduplog();
	dumpbadlog();
	ini_marks();
	printf("ready!\n");
	proceedchild("5157328");
	AcquireSRWLockExclusive(&rwcs);
	hastoken=-1;
	ReleaseSRWLockExclusive(&rwcs);
	system("PAUSE");
	buckdestroy();
	str_hashdestroy(usernamelist);
	str_hashdestroy_withfree(userrenamelist,s_free);
	str_hashdestroy(baduserlist);
	str_hashdestroy(dupuserlist);
	str_hashdestroy(logtype);
	str_hashdestroy(urltoken);
	_CrtDumpMemoryLeaks();
	return 0;
}
#else 
int main(int argc,char *argv[])
{
	int count=0,res=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);
	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(loadfromfile)
	{
		res=loaduserfromlocalfile();
	}
	else res=loadusernametable();
	if(res)
	{
		printf("Load username list error!\n");
		return -3;
	}
	if(loadrenamelog())
	{
		printf("Load user-rename list error!\n");
		return -4;
	}
	if(doallpage)
	{
		allpagequery(ns);
	}
	else query(searchstring,ns);
	if(pbl==NULL)
	{
		printf("No page!\n");
		return -5;
	}
	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();
		str_hashdestroy(usernamelist);
		str_hashdestroy_withfree(userrenamelist,s_free);
		str_hashdestroy(dupuserlist);
		str_hashdestroy(baduserlist);
		str_hashdestroy(logtype);
		str_hashdestroy(urltoken);
	}
	printf("---------------Ok done.---------------\n");
	fflush(stdout);
	system("PAUSE");
	return 0;
}
#endif