#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <process.h>
#include "mem.h"
#include "network.h"
#include "auth.h"
#include "convert.h"
struct problemlist
{
int pageid;
struct problemlist *next;
};
int threadc[1024];
char *threads[1024];
SRWLOCK rwcs;
CRITICAL_SECTION tcs;
CRITICAL_SECTION fcs;
CRITICAL_SECTION hcs;
int threadnumber=0;
int action=0;
struct problemlist *pbl=NULL;
int hideredirect=0;
int pagenum=0;
int hasquerytimeslimit=0;
int maxquerytimes=500;
int maxthread=256;
int logerr=0;
int test_mode=0;
const char *username;
const char *passwd;
FILE *debug;
FILE *err_log;
#define FULL_PROTECT 2
#define FULL_LIMIT 5000
#define SEMI_PROTECT 1
#define SEMI_LIMIT 500
#define NO_PROTECT 0
static int checkprotect(int pageid,int checklevel)
{
HTTP res;
char line[2048]={0},url[4096]={0},pttype[16],ptlevel[16],pttime[64];
char statusline[128];
int retry=0;
int haseditprot=0;
char *ptm[]={"type","level","expiry"};
char *ptv[3];
ptv[0]=pttype;
ptv[1]=ptlevel;
ptv[2]=pttime;
sprintf(url,"/w/api.php?action=query&format=xml&pageids=%d&prop=info&inprop=protection",pageid);
res=hopen();
for(retry=0;retry<20;retry++)
{
if(get(url,8888,1,res))
{
hclose(res);
res=hopen();
}
else
{
hgets(statusline,127,res);
if(strstr(statusline,"200")) break;
else
{
hclose(res);
res=hopen();
}
}
}
if(retry==20)
{
hclose(res);
return -1;
}
skipresponseheader(res);
do
{
if(xmlparsetag(res,line)==XML_PARSE_ERROR)
{
hclose(res);
return -1;
}
if(!strcmp(line,"pr"))
{
if(xmlparsearg(res,3,ptm,ptv)!=XML_HAS_VALUE)
{
hclose(res);
return -1;
}
if(!strcmp(pttime,"infinity"))
{
switch(checklevel)
{
case 1:
if(!strcmp(pttype,"edit")) haseditprot=1;
break;
case 2:
if(!strcmp(ptlevel,"sysop")||!strcmp(ptlevel,"templateeditor"))
{
if(!strcmp(pttype,"edit")) haseditprot=1;
}
break;
}
}
}
}while(!heof(res));
hclose(res);
return !haseditprot;
}
static int transcludesitu(int pageid)
{
HTTP res;
char line[2048]={0},url[4096]={0},snd[4096]={0},sroffset[2048]={0},offseto[512]={0},ids[16]={0};
char statusline[128];
int next=0,retry=0;
int count=0;
char *ctm[]={"ticontinue"};
char *ctv[1];
char *ttm[]={"pageid"};
char *ttv[1];
ctv[0]=offseto;
ttv[0]=ids;
sprintf(url,"/w/api.php?action=query&format=xml&prop=transcludedin&pageids=%d&tilimit=5000&tiprop=pageid",pageid);
do
{
strcpy(snd,url);
if(next)
{
strcat(snd,"&ticontinue=");
strcat(snd,sroffset);
}
res=hopen();
for(retry=0;retry<20;retry++)
{
if(get(snd,8888,1,res))
{
hclose(res);
res=hopen();
}
else
{
hgets(statusline,127,res);
if(strstr(statusline,"200")) break;
else
{
hclose(res);
res=hopen();
}
}
}
if(retry==20)
{
hclose(res);
return -1;
}
skipresponseheader(res);
next=0;
do
{
if(xmlparsetag(res,line)==XML_PARSE_ERROR) break;
if(!next)
{
if(!strcmp(line,"continue"))
{
if(xmlparsearg(res,1,ctm,ctv)==XML_HAS_VALUE)
{
URLEncode(offseto,strlen(offseto),sroffset,2047);
next=1;
}
else break;
}
}
if(!strcmp(line,"ti"))
{
if(xmlparsearg(res,1,ttm,ttv)==XML_HAS_VALUE) count++;
else break;
}
}while(!heof(res));
hclose(res);
if(next==1)
{
if(count>=FULL_LIMIT) return FULL_PROTECT;
}
else
{
if(count>FULL_LIMIT) return FULL_PROTECT;
else if(count>SEMI_LIMIT) return SEMI_PROTECT;
}
}while(next);
return NO_PROTECT;
}
static int fake_protect(int pageid,const char *type,const char *reason,const char *expiry)
{
EnterCriticalSection(&fcs);
fprintf(debug,"#pageid=%d type=%s reason=%s expiry=%s\n",pageid,type,reason,expiry);
fflush(debug);
LeaveCriticalSection(&fcs);
return 0;
}
static int protect(int pageid,const char *type,const char *reason,const char *expiry)
{
HTTP res;
char line[2048]={0},url[4096]={0};
char tp_enc[1024],rs_enc[1024],exp_enc[512];
char postbody[256],statusline[128];
char cur_token[128];
char err_type[8192];
char err_info[8192];
char *erm[]={"code","info"};
char *erv[2];
int has_err=0,token_err=0;
int retry=0;
erv[0]=err_type;
erv[1]=err_info;
URLEncode(type,strlen(type),tp_enc,1023);
URLEncode(reason,strlen(reason),rs_enc,1023);
URLEncode(expiry,strlen(expiry),exp_enc,511);
sprintf(url,"/w/api.php?action=protect&format=xml&pageid=%d&protections=%s&reason=%s&expiry=%s",pageid,tp_enc,rs_enc,exp_enc);
do
{
res=hopen();
while(1)
{
AcquireSRWLockShared(&rwcs);
if(hastoken) break;
else ReleaseSRWLockShared(&rwcs);
Sleep(100);
}
strcpy(cur_token,token);
ReleaseSRWLockShared(&rwcs);
sprintf(postbody,"&token=%s",cur_token);
if(post(url,postbody,8888,1,res))
{
hclose(res);
return -1;
}
hgets(statusline,127,res);
if(!strstr(statusline," 200"))
{
hclose(res);
return -2;
}
skipresponseheader(res);
token_err=has_err=0;
while(!heof(res))
{
if(xmlparsetag(res,line)==XML_HAS_VALUE)
{
if(!strcmp(line,"error"))
{
has_err=1;
xmlparsearg(res,2,erm,erv);
if((!strcmp(err_type,"notoken"))||(!strcmp(err_type,"badtoken")))
{
token_err=1;
}
break;
}
}
}
if(token_err)
{
AcquireSRWLockExclusive(&rwcs);
if(!strcmp(token,cur_token)) hastoken=0;
ReleaseSRWLockExclusive(&rwcs);
}
retry++;
hclose(res);
}while((token_err==1)&&(retry<3));
if(has_err==1)
{
if(logerr)
{
EnterCriticalSection(&fcs);
fprintf(err_log,"Error protecting page %d: type=%s reason=%s expiry=%s error=%s\nerror info=%s\n\n",pageid,type,reason,expiry,err_type,err_info);
fflush(err_log);
LeaveCriticalSection(&fcs);
}
return -3;
}
else return 0;
}
const char *reason_HRT=NULL;
static int proceedchild(int pageid)
{
switch(transcludesitu(pageid))
{
case SEMI_PROTECT:
if(checkprotect(pageid,SEMI_PROTECT)==1)
{
return test_mode==1?fake_protect(pageid,"edit=autoconfirmed",reason_HRT,"never"):protect(pageid,"edit=autoconfirmed",reason_HRT,"never");
}
break;
case FULL_PROTECT:
if(checkprotect(pageid,FULL_PROTECT)==1)
{
return test_mode==1?fake_protect(pageid,"edit=templateeditor|move=sysop",reason_HRT,"never"):protect(pageid,"edit=templateeditor|move=sysop",reason_HRT,"never");
}
break;
}
return 0;
}
void threadfunc(void *c)
{
int i=*(int *)c;
int ext=0;
int result=0;
int id=0;
struct problemlist *p;
while(!action) Sleep(1);
while(1)
{
EnterCriticalSection(&hcs);
if(p=pbl)
{
id=pbl->pageid;
pbl=pbl->next;
}
else ext=1;
LeaveCriticalSection(&hcs);
if(ext) break;
else
{
result=proceedchild(id);
s_free(p);
}
}
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 allpagequery(const char *ns)
{
HTTP f;
char line[2048]={0},url[4096]={0},id[512]={0},title[512]={0},sroffset[2048]={0},offseto[512]={0};
char statusline[128];
int status=0,next=0,retry=0,pageid=0;
struct problemlist *temp=0;
char *ctm[]={"apcontinue"};
char *ctv[1];
char *idm[]={"pageid","title"};
char *idv[2];
char *ptourl=url;
ctv[0]=offseto;
idv[0]=id;
idv[1]=title;
ptourl+=sprintf(url,"/w/api.php?action=query&format=xml&list=allpages&apnamespace=%s&aplimit=5000&apfilterredir=%s",ns,hideredirect?"nonredirects":"all");
do
{
if(next)
{
sprintf(ptourl,"&apcontinue=%s",sroffset);
}
else *ptourl=0;
f=hopen();
for(retry=0;retry<20;retry++)
{
if(get(url,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;status=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;
pagenum++;
}
}
}while(!heof(f));
hclose(f);
if(hasquerytimeslimit)
{
if(--maxquerytimes<=0) break;
}
}while(next);
return 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&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&0x80)
{
printf(
"\tInvalid debug file.\n"
"\t\tCannot open the specified debug file.\n"
);
}
if(code&0x100)
{
printf(
"\tInvalid log file.\n"
"\t\tCannot open the specified log file.\n"
);
}
return;
}
static int parsearg(int argc,const char *argv[])
{
int cur_arg=0;
unsigned int err=0;
for(cur_arg=1;cur_arg<argc;cur_arg++)
{
if(argv[cur_arg][0]=='-'&&(argv[cur_arg+1]&&argv[cur_arg+1][0]!='-'))
{
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 'p':
passwd=argv[cur_arg+1];
if(strlen(passwd)>64)
{
err|=0x8;
}
else
{
err|=0x10;
}
cur_arg++;
break;
case 'T':
maxthread=atoi(argv[cur_arg+1]);
if(maxthread<1||maxthread>1024) maxthread=32;
cur_arg++;
break;
case 'm':
maxquerytimes=atoi(argv[cur_arg+1]);
if(maxquerytimes>0) hasquerytimeslimit=1;
break;
case 'd':
if((debug=fopen(argv[cur_arg+1],"w+"))!=NULL)
{
test_mode=1;
}
else
{
err|=0x80;
}
break;
case 'l':
if((err_log=fopen(argv[cur_arg+1],"a+"))!=NULL)
{
fprintf(err_log,"--------- Logging... ---------\n");
logerr=1;
}
else
{
err|=0x100;
}
break;
}
}
}
if(0x1+0x10==err) return 0;
else
{
displayerr(err);
return err;
}
}
static void ini_marks()
{
reason_HRT=G2U("bot: [[WP:HRT|high-risk templates/高风险模板/高風險模板]]");
return;
}
static void printusage()
{
printf("usage: -u username -p passwd [-T concurrency -d debug_file -l err_log -m maxquery]\n");
return ;
}
#ifndef _DEBUG
int main(int argc,char **argv)
{
int count=0;
HANDLE tk_thread=0;
buckini(20);
InitializeSRWLock(&rwcs);
InitializeCriticalSection(&tcs);
InitializeCriticalSection(&hcs);
InitializeCriticalSection(&fcs);
if(parsearg(argc,argv))
{
printusage();
return -1;
}
if(login(username,passwd))
{
printf("Login error!\n");
return -2;
}
ini_marks();
if(!test_mode)
{
tk_thread=(HANDLE)_beginthread(tokenmanage,0,0);
}
allpagequery("10");
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);
if(!test_mode) WaitForSingleObject(tk_thread,INFINITE);
buckdestroy();
}
else printf("%d threads left.\n",threadnumber);
printf("---------------Ok done.---------------\n");
fflush(stdout);
if(logerr) fclose(err_log);
if(test_mode) fclose(debug);
return 0;
}
#else
int main(void)
{
buckini(20);
InitializeSRWLock(&rwcs);
InitializeCriticalSection(&tcs);
InitializeCriticalSection(&hcs);
InitializeCriticalSection(&fcs);
login("Antigng@Antigng","");
ini_marks();
_beginthread(tokenmanage,0,0);
Sleep(5000);
logerr=1;
err_log=stdout;
proceedchild(557733);
return 0;
}
#endif