#include <stdio.h>
#include <string.h>
#include <process.h>
#include <windows.h>
#include "mem.h"
#include "network.h"
#include "convert.h"
#include "auth.h"
/*Cookies & session*/
struct _cookie
{
char name[512];
char value[512];
struct _cookie *next;
};
struct _cookie *cookielist=NULL;
char session[4096]={0};
int sessionlength=0;
static int destroycookielist()
{
struct _cookie *pre,*temp;
temp=pre=cookielist;
while(temp)
{
pre=temp;
temp=temp->next;
s_free(pre);
}
cookielist=NULL;
return 0;
}
static int addtocookielist(const char *name,const char *value)
{
struct _cookie *head=cookielist,*pre=NULL;
while(head)
{
if(!strcmp(head->name,name)) break;
pre=head;
head=head->next;
}
if(!head)
{
head=(struct _cookie *)s_malloc(sizeof(struct _cookie));
if(pre)
{
pre->next=head;
}
else cookielist=head;
strcpy(head->name,name);
strcpy(head->value,value);
head->next=0;
return 1;
}
else
{
strcpy(head->value,value);
return 0;
}
}
static int deletefromcookielist(const char *name)
{
struct _cookie *pre,*cur;
pre=cur=cookielist;
while(cur)
{
if(!strcmp(cur->name,name))
{
if(cur==cookielist)
{
cookielist=cookielist->next;
s_free(cur);
}
else
{
pre->next=cur->next;
s_free(cur);
}
return 1;
}
pre=cur;
cur=cur->next;
}
return 0;
}
static void generatesessionfromcookies()
{
struct _cookie *head;
char *ptosession=session;
head=cookielist;
*ptosession=0;
sessionlength=0;
while(head)
{
int length=sprintf(ptosession,"%s=%s;",head->name,head->value);
ptosession+=length;
sessionlength+=length;
head=head->next;
}
return ;
}
static int cookieexist(const char *name)
{
struct _cookie *cur;
cur=cookielist;
while(cur)
{
if(!strcmp(cur->name,name))
{
return 1;
}
cur=cur->next;
}
return 0;
}
static int splitcookie(const char *cookie,char *name,char *value)
{
int counter=0;
const char *val;
*name=*value=0;
while(cookie[counter]==' ')
{
counter++;
}
val=strchr(cookie+counter,'=');
if(val)
{
strncpy(name,cookie+counter,val-cookie-counter);
name[val-cookie-counter]=0;
strcpy(value,val+1);
return 1;
}
return 0;
}
static int validatecookie(const char *value,const char *attr)
{
if(!strcmp(value,"deleted"))
{
return 0;
}
else
{
const char *start=strstr(attr,"Max-Age=");
if(start)
{
const char *end=strstr(start+8,";");
char time[32];
if(end)
{
strncpy(time,start+8,end-start-7);
time[end-start-8]=0;
}
else
{
strncpy(time,start+8,30);
time[30]=0;
}
if(atoi(time)<20) return 0;
}
}
return 1;
}
static int deletesession(const char *name)
{
deletefromcookielist(name);
generatesessionfromcookies();
return !(*session);
}
static int updatesession(const char *name,const char *value)
{
if(sessionlength+strlen(name)+strlen(value)<2048)
{
addtocookielist(name,value);
generatesessionfromcookies();
}
return !(*session);
}
void sessionmanage(const char *cookie,const char *attr)
{
char name[512],value[512];
if(splitcookie(cookie,name,value))
{
if(validatecookie(value,attr))
{
AcquireSRWLockExclusive(&rwcs);
updatesession(name,value);
ReleaseSRWLockExclusive(&rwcs);
}
else
{
AcquireSRWLockShared(&rwcs);
if(cookieexist(name))
{
ReleaseSRWLockShared(&rwcs);
AcquireSRWLockExclusive(&rwcs);
deletesession(name);
ReleaseSRWLockExclusive(&rwcs);
}
else
{
ReleaseSRWLockShared(&rwcs);
}
}
}
return ;
}
/*Login & logout*/
static int checkloginsucceed(HTTP h)
{
char line[2048];
int suc=0;
while(!heof(h))
{
hgets(line,2047,h);
if(strstr(line,"Success"))
{
suc=1;
break;
}
}
return suc;
}
int login(const char *username,const char *password)
{
HTTP f;
int tokenfound=0;
char buf[1024];
char postbody[1024],logintoken[128],raw_logintoken[128];
char *lgm[]={"logintoken"};
char *lgv[1];
lgv[0]=raw_logintoken;
f=hopen();
if(get("/w/api.php?action=query&format=xml&meta=tokens&type=login",8888,0,f))
{
hclose(f);
return 1;
}
skipresponseheader(f,1);
while(!heof(f))
{
xmlparsetag(f,buf);
if(!strcmp(buf,"tokens"))
{
xmlparsearg(f,1,lgm,lgv);
URLEncode(raw_logintoken,strlen(raw_logintoken),logintoken,127);
tokenfound=1;
break;
}
}
hclose(f);
if(!tokenfound) return 1;
sprintf(postbody,"&lgname=%s&lgpassword=%s&lgtoken=%s",username,password,logintoken);
f=hopen();
if(post("/w/api.php?action=login&format=xml",postbody,8888,1,f))
{
hclose(f);
return 1;
}
skipresponseheader(f,1);
if(!checkloginsucceed(f))
{
hclose(f);
return 1;
}
hclose(f);
printf("Auth complete.\n");
return 0;
}
static int do_logout()
{
HTTP res;
char content[512],statusline[128];
sprintf(content,"&token=%s",token);
res=hopen();
if(post("/w/api.php?action=logout&format=xml",content,8888,1,res))
{
hclose(res);
return -1;
}
hgets(statusline,126,res);
if(!strstr(statusline,"200"))
{
hclose(res);
return -2;
}
if(skipresponseheader(res,1))
{
hclose(res);
return -3;
}
hclose(res);
return 0;
}
void logout()
{
if(token[0])
{
if(!do_logout())
{
printf("Sucessfully logged out.\n");
}
}
token[0]=0;
session[0]=0;
sessionlength=0;
destroycookielist();
return ;
}
/*Tokens*/
char token[128]={0};
int hastoken=0;
static int gettoken()
{
HTTP f;
int flag=0;
char buf[1024];
char raw_token[128];
char *tkm[]={"csrftoken"};
char *tkv[1];
tkv[0]=raw_token;
f=hopen();
if(get("/w/api.php?action=query&format=xml&meta=tokens",8888,1,f))
{
hclose(f);
goto TOKEN_NOT_FOUND;
}
if(skipresponseheader(f,1))
{
hclose(f);
goto TOKEN_NOT_FOUND;
}
while(!heof(f))
{
xmlparsetag(f,buf);
if(!strcmp(buf,"tokens"))
{
xmlparsearg(f,1,tkm,tkv);
flag=1;
break;
}
}
hclose(f);
if(flag)
{
if(!strcmp(raw_token,"+\\"))
{
fprintf(stderr,"Warning! Logout.\n");
exit(-1);
}
AcquireSRWLockExclusive(&rwcs);
URLEncode(raw_token,strlen(raw_token),token,127);
if(!hastoken) hastoken=1;
ReleaseSRWLockExclusive(&rwcs);
return 0;
}
TOKEN_NOT_FOUND:
printf("Token not found.\n");
return -1;
}
void tokenmanage(void *p)
{
p=NULL;
for(;;)
{
AcquireSRWLockShared(&rwcs);
if(!hastoken)
{
ReleaseSRWLockShared(&rwcs);
printf("Change token.\n");
gettoken();
}
else if(hastoken==-1)
{
ReleaseSRWLockShared(&rwcs);
break;
}
else ReleaseSRWLockShared(&rwcs);
Sleep(1);
}
return;
}