#include #include #include #include #include #include #include #include #include #include #include #include "tlmpdoc.h" #include "tlmpdoc.m" static W_SSTRING adding ("adding"); static W_SSTRING changing ("changing"); static W_SSTRING deleting ("deleting"); static W_SSTRING publish ("publish"); static W_SSTRING backup ("backup"); static W_SSTRING title ("title"); static W_SSTRING text ("text"); static W_SSTRING editing ("editing","","S"); static W_SSTRING user ("user","","S"); static W_SSTRING password ("passwd","","S"); static W_SSTRING password1 ("passwd1","","S"); static W_SSTRING password2 ("passwd2","","S"); static W_INT admin("admin",0); static W_SSTRING auser("auser",""); static W_SSTRING email ("email",""); struct WIKINODE: public ARRAY_OBJ{ string level; string title; string text; bool deleted; // This node is deleted bool edited; // This is the edit copy or the public one int nodeid; }; typedef ARRAY_OBJS WIKINODES; static void tlmpwiki_setkey (char *key, int tbno[], int level) { for (int j=0; j static int loop ( WIKINODES &nodes, int cur[], int level, int pos) { glocal WIKINODES *nodes = &nodes; glocal int *cur = cur; glocal int level = level; glocal int pos = pos; for (; glocal.poslevel.c_str(); int cmp = strcmp(sectid,glocal.tmp); if (cmp==0){ glocal int curpos = glocal.pos; glocal.pos++; WIKINODE *n = nodes.getitem(glocal.curpos); const char *title = n->title.c_str(); string tmp; if (n->edited){ tmp = string_f ("%s (modified)",title); title = tmp.c_str(); } (sectid,title); htmlout (glocal.nodes->getitem(glocal.curpos)->text.c_str()); htmlout ("\n"); glocal.pos = loop (*glocal.nodes,glocal.cur,glocal.level+1,glocal.pos); cur[level]++; }else if(cmp > 0){ break; }else{ glocal.pos++; } } cur[level] = 1; return glocal.pos; } /* Edit a node. Return true if the node has been updated in the SQL database */ static bool tlmpwiki_edit( bool newnode, WIKINODES &nodes, const char *key, int wikiid) { if (key[0] == '-') key++; glocal bool newnode = newnode; glocal bool ret = false; glocal const char *key = key; glocal WIKINODES *nodes = &nodes; glocal int wikiid = wikiid; extern W_INT step1,step2,step3,step4; FORM_HIDDEN hstep1(step1); FORM_HIDDEN hstep2(step2); FORM_HIDDEN hstep3(step3); FORM_HIDDEN hstep4(step4); { int tbno[4]={0,0,0,0}; for (int i=0; key[i] != '\0'; i++){ tbno[i] = key[i] - 'a' + 1; } step1 = tbno[0]; step2 = tbno[1]; step3 = tbno[2]; step4 = tbno[3]; } ("wiki"); if (first){ if (glocal.newnode){ tlmpweb_title ("Adding a node"); printf ("

Adding a node

\n"); }else{ tlmpweb_title ("Changing a node"); printf ("

Changing a node

\n"); for (int i=0; igetnb(); i++){ WIKINODE *n = glocal.nodes->getitem(i); if (n->level.compare(glocal.key)==0){ title = n->title; text = n->text; break; } } } } printf ("

\n"); printf ("
%s","Title"); field_string (title,"size=50"); printf ("
%s","Text"); field_textarea (text,20,70,""); printf ("
\n");
bool ret = false; if (title.empty()){ tlmpweb_error ("Title can't be empty"); }else if (text.empty()){ tlmpweb_error ("Text can't be empty"); }else{ ret = true; } return ret; if (glocal.newnode){ // Find the last node in this level string tmp; for (int i=0; i<26; i++){ tmp = string_f("%s%c",glocal.key,i+'a'); int j; for (j=0; jgetnb(); j++){ WIKINODE *n = glocal.nodes->getitem(j); if (n->level.compare(tmp)==0) break; } if (j == glocal.nodes->getnb()) break; } NSQL_ENCODE enc; sql_action ("insert into nodes" " set wikiid=%d,title='%s',content='%s',level='%s',edited='Y',deleted=' '" ,glocal.wikiid,enc.enc(title.c_str()),enc.enc(text.c_str()),tmp.c_str()); }else{ ("select level from nodes" " where wikiid=%d and level='%s' and edited='Y'" ,glocal.wikiid,glocal.key); // Ok, the edited node exist, we update NSQL_ENCODE enc; sql_action ("update nodes set title='%s',content='%s'" " where level='%s' and wikiid=%d" ,enc.enc(title.c_str()),enc.enc(text.c_str()),glocal.key,glocal.wikiid); // No edited node, only a published one. We insert NSQL_ENCODE enc; sql_action ("insert into nodes" " set wikiid=%d,title='%s',content='%s',level='%s',edited='Y',deleted=' '" ,glocal.wikiid,enc.enc(title.c_str()),enc.enc(text.c_str()),glocal.key); } glocal.ret = true;
return glocal.ret; }
static void tlmpwiki_button (const char *parms, const char *title) { extern W_INT step1,step2,step3,step4; printf ("\n"); string tmp = string_f ("s1=%d&s2=%d&s3=%d&s4=%d&%s",step1.getval() ,step2.getval(),step3.getval(),step4.getval() ,parms); url_self (tmp,"%s",title); printf ("\n"); } static void wiki_do (_F_wiki &c, int wikiid, const char *title) { glocal _F_wiki *c = &c; glocal WIKINODES nodes; glocal int wikiid = wikiid; glocal bool show = false; glocal time_t last = 0; (); string edfilter; if (editing.empty()){ edfilter = " and edited<>'Y'"; } glocal.nodes.remove_all(); ("select level,title,content,unix_timestamp(dater),deleted,edited,nodeid from nodes" " where wikiid=%d and deleted<>'Y'%s" " order by level,edited",glocal.wikiid,edfilter.c_str()); WIKINODE *node = new WIKINODE; node->level = row[0]; node->title = row[1]; node->text = row[2]; node->deleted = toupper(row[4][0]) == 'Y'; node->edited = toupper(row[5][0]) == 'Y'; node->nodeid = atoi(row[6]); glocal.nodes.add (node); time_t dater = atoi(row[3]); // printf ("dater = %d %d\n",dater,glocal.last); if (dater > glocal.last) glocal.last = dater; // Remove the published node if there is one edited if (editing.is_filled()){ for (int i=0; ilevel.compare(n2->level)==0){ glocal.nodes.remove_del(i); } } } oo.exec(); tlmpweb_setmodified (glocal.last); if (adding.is_filled()){ FORM_HIDDEN hadding(adding); glocal.show = tlmpwiki_edit(true,glocal.nodes,adding.c_str() ,glocal.wikiid); if (glocal.show) oo.exec(); }else if (changing.is_filled()){ FORM_HIDDEN hchanging(changing); glocal.show = tlmpwiki_edit(false,glocal.nodes,changing.c_str() ,glocal.wikiid); if (glocal.show) oo.exec(); }else if (deleting.is_filled()){ const char *key = deleting.c_str(); if (key[0] == '-') key++; int len = strlen(key); int last = len-1; // Delete the node and the children // and reassign the one following ones for (int i=0; ilevel.compare(0,len,key,len)==0){ sql_action ("update nodes set deleted='Y' where wikiid=%d" " and level='%s'",glocal.wikiid,n->level.c_str()); }else if (n->level.compare(0,last,key,last)==0 && n->level.compare(key) > 0){ string tmp = n->level; tmp[last]--; sql_action ("update nodes set level='%s' where wikiid=%d" " and level='%s'",tmp.c_str(),glocal.wikiid,n->level.c_str()); } } glocal.show = true; oo.exec(); }else if (publish.is_filled()){ const char *key = publish.c_str(); bool doone = true; if (key[0] == '-'){ key++; }else if (key[0] == ':'){ key++; doone = false; }else{ key="99999"; } int len = strlen(key); for (int i=0; ilevel.c_str(); if (strncmp(wkey,key,len)==0 && n->edited){ // Delete the currently published node sql_action ("update nodes set deleted='Y' where level='%s'" " and deleted<>'Y' and edited<>'Y' and wikiid=%d" ,wkey,glocal.wikiid); // Then turn the edited node into a public one sql_action ("update nodes set edited=' ' where level='%s'" " and deleted<>'Y' and edited='Y' and wikiid=%d" ,wkey,glocal.wikiid); if (doone) break; } } glocal.show = true; oo.exec(); string cmd = string_f ("tlmpdoc --upddoc %s",tlmpweb_curpath()); (cmd,20); return 0; }else if (glocal.nodes.getnb()==0){ if (editing.is_filled()){ url_self ("adding=-","%s","Adding the first node"); }else{ url_self ("editing=1","%s","Editing the document"); } }else{ glocal.show = true; } if (glocal.show){ (title); glocal.c->abstract(); int cur[10]; memset (cur,1,sizeof(cur)); loop (glocal.nodes,cur,0,0); printf ("\n"); if (editing.is_filled()){ char key[11],parms[40]; tlmpwiki_setkey (key,tbno,level); snprintf (parms,sizeof(parms)-1,"adding=-%s",key); tlmpwiki_button (parms,"Adding a node"); if (level > 0){ snprintf (parms,sizeof(parms)-1,"changing=-%s",key); tlmpwiki_button (parms,"Changing this node"); snprintf (parms,sizeof(parms)-1,"deleting=-%s",key); tlmpwiki_button (parms,"Delete this node"); snprintf (parms,sizeof(parms)-1,"publish=-%s",key); tlmpwiki_button (parms,"Publish this node"); snprintf (parms,sizeof(parms)-1,"publish=:%s",key); tlmpwiki_button (parms,"Publish section"); }else{ tlmpwiki_button ("publish=:","Publish document"); } tlmpwiki_button ("editing=","View public version"); tlmpwiki_button ("admin=1","Administration"); }else{ tlmpwiki_button ("editing=1","Editing this document"); extern W_INT full; if (full){ tlmpwiki_button ("full=0","Show content"); }else{ tlmpwiki_button ("full=1","Hide content"); } } printf ("
\n"); htmlprintf ("
\n");
url_self ("dp=0",MSG_R(I_ONEBIG)); htmlprintf ("
\n");
} }
static bool tlmpwiki_checkauth(int wikiid) { glocal bool ret = false; NSQL_ENCODE enc; // printf ("wikiid %d user :%s: passwd :%s:\n",wikiid,user.get(),password.get()); ("select count(*) from authors" " where (wikiid=%d and user='%s' and passwd=password('%s'))" " or (wikiid=0 and user='%s' and passwd=password('%s'))" ,wikiid,enc.enc(user.c_str()),enc.enc(password.c_str()) ,enc.enc(user.c_str()),enc.enc(password.c_str())); glocal.ret = atoi(row[0])==1; return glocal.ret; } static bool tlmpwiki_auth(int wikiid) { glocal bool ret = false; glocal int wikiid = wikiid; tlmpweb_title ("You must authenticate"); ("wikiauth"); printf ("

Please identify yourself

\n"); printf ("

"); printf ("

\n"); printf ("
%s","User ID"); field_string (user,"size=20"); printf ("
%s","Password"); field_password (password,""); printf ("
\n");
int ret = false; if (tlmpwiki_checkauth(glocal.wikiid)){ ret = true; }else{ tlmpweb_error ("Invalid user or password"); } return ret; glocal.ret = true;
return glocal.ret; }
static void tlmpwiki_printauthors(int wikiid) { tlmpweb_title ("Administrators/Authors"); ("select user,email from authors" " where wikiid=%d order by user",wikiid); printf ("

Administrators/Authors

\n"); printf ("
\n"); printf ("
AdministratorEmail\n"); printf ("
\n"); url_self ("admin=3","Add a new author"); printf ("
\n"); url_self ("admin=&editing=1","Back to document edition"); printf ("
\n");
printf (""); string tmp = string_f ("admin=2&auser=%s",row[0]); url_self (tmp,row[0]); printf ("%s\n",row[1]);
}
static bool tlmpwiki_userexist (int wikiid, const char *user) { glocal bool ret = false; ("select count(*) from authors" " where wikiid=%d and user='%s'",wikiid,user); glocal.ret = row[0][0] == '1'; return glocal.ret; } static void tlmpwiki_admin (int wikiid) { glocal int wikiid = wikiid; if (admin == 1){ tlmpwiki_printauthors (wikiid); }else if (admin == 2 || admin == 3){ glocal bool print = false; glocal bool exist = tlmpwiki_userexist (wikiid,auser.c_str()); FORM_HIDDEN f(admin); tlmpweb_title ("One author"); ("wikiadmin"); if (first && glocal.exist){ NSQL_ENCODE enc; ("select email from authors" " where wikiid=%d and user='%s'" ,glocal.wikiid,enc.enc(auser.c_str())); email = row[0]; } printf ("

One author

\n"); printf ("

\n"); printf ("

\n"); printf ("\n"); } printf ("
%s","User ID"); if (glocal.exist){ printf ("%s\n",auser.c_str()); field_hidden (auser); }else{ field_string (auser,"size=20"); } printf ("
%s","Email"); field_string (email,"size=50"); if (glocal.exist){ printf ("
Enter new password
\n" "to change, leave empty to keep
%s","Password"); field_password (password1,""); printf ("
%s","Password (retype)"); field_password (password2,""); printf ("
\n");
bool ret = false; if (!glocal.exist && auser.empty()){ tlmpweb_error ("You must specify the user ID"); }else if (!glocal.exist && tlmpwiki_userexist(glocal.wikiid,auser.c_str())){ tlmpweb_error ("User %s already exist",auser.c_str()); }else if (!glocal.exist && password1.empty()){ tlmpweb_error ("Password may not be empty"); }else if (password1.is_filled() && password1.compare(password2)!=0){ tlmpweb_error ("Passwords differs, please reenter"); }else{ ret = true; } return ret; if (glocal.exist){ NSQL_ENCODE enc; if (password1.is_filled()){ sql_action ("update authors set passwd=password('%s'),email='%s'" " where user='%s' and wikiid=%d" ,enc.enc(password1.c_str()),enc.enc(email.c_str()),enc.enc(auser.c_str()) ,glocal.wikiid); }else{ sql_action ("update authors set email='%s'" " where user='%s' and wikiid=%d" ,enc.enc(email.c_str()) ,enc.enc(auser.c_str()),glocal.wikiid); } }else{ NSQL_ENCODE enc; sql_action ("insert into authors (user,email,passwd,wikiid)" " values" " ('%s','%s',password('%s'),%d)" ,enc.enc(auser.c_str()),enc.enc(email.c_str()),enc.enc(password1.c_str()) ,glocal.wikiid); } glocal.print = true;
if (glocal.print){ tlmpwiki_printauthors (glocal.wikiid); } } }
/* Tell if we are executed using /usr/bin/tlmpdoc, either by root or by user apache. The goal is to bypass the login required for private document when trying to update the docsession database. */ static bool tlmpwiki_is_tlmpdoc() { glocal bool ret = false; pid_t pid = getppid(); char path[PATH_MAX]; snprintf (path,sizeof(path)-1,"/proc/%u/exe",pid); char buf[PATH_MAX]; int len = readlink(path,buf,sizeof(buf)); if (len > 0){ buf[len] = '\0'; if (strcmp(buf,"/usr/bin/tlmpdoc")==0){ snprintf (path,sizeof(path)-1,"/proc/%u/status",pid); (path,false); bool ret = true; if (strncmp(line,"Uid:",4)==0){ uid_t uid = atoi(str_skip(line+4)); if (uid == 0){ glocal.ret = true; }else{ struct passwd *p = getpwnam("apache"); if (p != NULL && p->pw_uid == uid){ glocal.ret = true; } } ret = false; } return ret; } } return glocal.ret; } void wiki ( _F_wiki &c, const char *doc, const char *title, bool priv, // This document may only be accessed by authors const char *database) { glocal _F_wiki *c = &c; glocal const char *doc = doc; glocal const char *title = title; glocal int wikiid = -1; glocal bool priv = priv; if (priv){ // We have to tell if we are accessed by tlmpdoc // when we publish the document. We bypass security // in this case. if (tlmpwiki_is_tlmpdoc()) glocal.priv = false; } string tmp = string_f ("wiki-%s",doc); query_setdefaultdb ("localhost",database); ("select wikiid from wikis where document='%s'" ,doc); glocal.wikiid = atoi(row[0]); // Create the entry for the document sql_action ("insert into wikis set document='%s'",glocal.doc); ("select wikiid from wikis where document='%s'" ,glocal.doc); glocal.wikiid = atoi(row[0]); (tmp.c_str()); return true; bool ok = false; if (!glocal.priv && editing.empty() && admin == 0){ ok = true; }else if (tlmpwiki_checkauth (glocal.wikiid)){ ok = true; }else{ ok = tlmpwiki_auth(glocal.wikiid); } if (ok){ if (admin > 0){ tlmpwiki_admin (glocal.wikiid); }else{ (); if(editing.is_filled()){ wiki_do (*glocal.c,glocal.wikiid,glocal.title); }else{ wiki_do (*glocal.c,glocal.wikiid,glocal.title); } } } } void wiki ( _F_wiki &c, const char *doc, const char *title) { wiki (c,doc,title,false,"wikis"); }