#include #include #include #include #include #include "tlmpdoc.h" #include "internal.h" #include class _F_docsession_private{ }; static vector keys; static const char *docsession_id; // ID of the document static int docid=-1; // Key to update the database static int userid; static char usr_lastvisit[20]; // When the user last visited this document static NSQL *sq; class DOCNODE_STATE: public ARRAY_OBJ{ public: string key; char dater[20]; // Last revision date for this node int sectionid; /*~PROTOBEG~ DOCNODE_STATE */ public: DOCNODE_STATE (const char *_key, const char *_dater, int _sectionid); /*~PROTOEND~ DOCNODE_STATE */ }; PUBLIC DOCNODE_STATE::DOCNODE_STATE( const char *_key, const char *_dater, int _sectionid) : key(_key) { strcpy (dater,_dater); sectionid = _sectionid; } class DOCNODE_STATES: public ARRAY{ public: /*~PROTOBEG~ DOCNODE_STATES */ public: DOCNODE_STATE *getitem (int no)const; DOCNODE_STATE *locate (const char *key)const; DOCNODE_STATE *locate (int sectionid)const; /*~PROTOEND~ DOCNODE_STATES */ }; PUBLIC DOCNODE_STATE *DOCNODE_STATES::getitem(int no) const { return (DOCNODE_STATE*)ARRAY::getitem(no); } PUBLIC DOCNODE_STATE *DOCNODE_STATES::locate(const char *key) const { DOCNODE_STATE *ret = NULL; int n = getnb(); for (int i=0; ikey == key){ ret = node; break; } } return ret; } PUBLIC DOCNODE_STATE *DOCNODE_STATES::locate(int sectionid) const { DOCNODE_STATE *ret = NULL; int n = getnb(); for (int i=0; isectionid == sectionid){ ret = node; break; } } return ret; } static DOCNODE_STATES current; // The current revision of the various sections static DOCNODE_STATES user; // What the user have seen so far // We are using the same structure even // if there is no key in this one. /* Return the status (reader) of a text section. */ DOCNODE_STATUS docsession_getstatus () { DOCNODE_STATUS ret = DOCNODE_OLD; if (tlmpdoc_buildkey == 0 && docid != -1){ const char *key = keys.back().c_str(); DOCNODE_STATE *cur = current.locate (key); if (cur != NULL){ DOCNODE_STATE *usr = user.locate (cur->sectionid); if (usr == NULL){ if (strcmp(cur->dater,usr_lastvisit)>0){ ret = DOCNODE_NEW; }else{ ret = DOCNODE_NEVERSEEN; } }else{ if (strcmp(usr->dater,cur->dater)==0){ ret = DOCNODE_OLD; }else{ ret = DOCNODE_MODIFIED; } } } } return ret; } /* Tells if there is new or modified stuff in sub-sections. */ DOCNODE_STATUS docsession_getsubstatus () { DOCNODE_STATUS ret = DOCNODE_OLD; if (tlmpdoc_buildkey == 0 && docid != -1){ const char *key = keys.back().c_str(); int lenkey = strlen(key); int n=current.getnb(); for (int i=0; ikey.c_str(); if (strncmp(key,ckey,lenkey)==0 && ckey[lenkey] == '\t'){ // This is a sub-node DOCNODE_STATE *usr = user.locate (cur->sectionid); if (usr == NULL){ if (ret == DOCNODE_OLD) ret = DOCNODE_NEVERSEEN; if (strcmp(cur->dater,usr_lastvisit)>0){ ret = DOCNODE_NEW; // Highest precedence, no need to search further break; } }else{ if (strcmp(usr->dater,cur->dater)!=0){ ret = DOCNODE_MODIFIED; } } } } } return ret; } /* Write the
  • statement to introduce a section */ void docsession_putli() { if (tlmpdoc_buildkey != 0 || docid == -1){ htmlprintf ("
  • "); }else{ DOCNODE_STATUS status = docsession_getstatus(); if (status == DOCNODE_OLD){ htmlprintf ("
  • "); }else if (status == DOCNODE_MODIFIED){ htmlprintf ("
  • "); }else if (status == DOCNODE_NEW){ htmlprintf ("
  • "); }else{ htmlprintf ("
  • "); } } } /* Write the status of sub-section at the end of the
  • statement. */ void docsession_putendli() { if (tlmpdoc_buildkey == 0 && docid != -1){ DOCNODE_STATUS status = docsession_getsubstatus(); if (status == DOCNODE_OLD){ }else if (status == DOCNODE_MODIFIED){ htmlprintf (" () "); }else if (status == DOCNODE_NEW){ htmlprintf (" () "); }else{ htmlprintf (" ... "); } } } /* Put something to present the status of the section. */ void docsession_qualify() { if (tlmpdoc_buildkey != 0){ htmlprintf ("##--##%s\n",keys.back().c_str()); }else{ #if 0 DOCNODE_STATUS status = docsession_getstatus(); static const char *tb[]={ "OLD","NEVER","MODIFIED","NEW" }; htmlprintf ("%s ",tb[status]); #endif } } /* Record that the current node was presented to the reader */ void docsession_wasseen() { if (docsession_getstatus()!= DOCNODE_OLD){ const char *key = keys.back().c_str(); DOCNODE_STATE *cur = current.locate (key); if (cur == NULL){ tlmpweb_error ("tlmpdoc: can't locate current section\n"); }else{ DOCNODE_STATE *usr = user.locate (cur->sectionid); if (usr == NULL){ sql_action (*sq,"insert into userview (userid,docid,sectionid,lastvisit)" " values (%d,%d,%d,'%s')" ,userid,docid,cur->sectionid,cur->dater); }else{ sql_action (*sq,"update userview set lastvisit='%s'" " where userid=%d and docid=%d and sectionid=%d" ,cur->dater,userid,docid,cur->sectionid); } if (usr_lastvisit[0] == '\0'){ sql_action (*sq,"insert into userview" " (docid,userid,sectionid,lastvisit)" " values" " (%d,%d,-1,now())" ,docid,userid); }else{ sql_action (*sq,"update userview set lastvisit=now()" " where userid=%d and docid=%d and sectionid=-1" ,userid,docid); } } } } void docsession_endsection() { if (tlmpdoc_buildkey != 0){ htmlprintf ("##++##\n"); } } void docsession_push (const char *id) { auto n = keys.size(); if (n == 0){ keys.emplace_back(id); }else{ string &last = keys[n-1]; keys.push_back(string_f("%s\t%s",last.c_str(),id)); } } void docsession_pop () { keys.pop_back (); } static void docsession_manage (_F_docsession &c, const char *id) { docsession_id = id; current.remove_all(); user.remove_all(); NSQL_ENCODE enc; docid = -1; usr_lastvisit[0] = '\0'; // We need info about the sections in this documents (*sq,"select docid from documents" " where document='%s'" ,enc.enc(id)); // This document is not registered in the database tlmpweb_error ("No document %s in database
    \n",docsession_id);
    docid = atoi(row[0]); // We need info about the sections in this documents (*sq,"select section,dater,sectionid from revisions" " where docid=%s order by section",row[0]); current.add (new DOCNODE_STATE(row[0],row[1],atoi(row[2]))); // We need info about what the user has seen (*sq,"select sectionid,lastvisit from userview" " where userid=%d and docid=%s" ,userid,row[0]); int sectionid = atoi(row[0]); if (sectionid==-1) strcpy (usr_lastvisit,row[1]); user.add (new DOCNODE_STATE("",row[1],sectionid));
    c.body(); docsession_id = NULL; docid = -1; }
    /* Make sure the cookie value is made of all alphanum and a - and it is not too long. */ static bool docsession_validcookie (const char *s) { bool ret = true; if (strlen(s)>30){ ret = false; }else{ while (*s != '\0'){ if (*s != '-' && !isalnum(*s)){ ret = false; break; } s++; } } return ret; } void docsession_do (_F_docsession &c, const char *id) { _F_docsession_private priv; c.priv = &priv; if (tlmpdoc_buildkey != 0){ htmlprintf ("##__##%s\n",id); tlmpdoc_vdepth.setinitval ("0"); c.body(); }else{ NSQL nsql ("localhost","docsession"); sq = &nsql; // We need to identify this user const char *cookie = tlmpweb_getcookie("docsession"); time_t ti = time(NULL); // tlmpweb_error ("cookie :%s:
    \n",cookie); if (cookie == NULL){ // This a new user char random[20]; websession_setrandom (random); char val[40]; sprintf (val,"%lu-%s",ti,random); sql_action (*sq,"insert into users (user) values ('%s')",val); (*sq,"select userid from users where user='%s'" ,val); userid = atoi(row[0]); websession_setcookie ("docsession",val,ti+360*24*60*60); docsession_manage (c,id); }else if (docsession_validcookie(cookie)){ // This is a known user userid = 0; glocal const char *cookie = cookie; (*sq,"select userid from users where user='%s'" ,cookie); // New user sql_action (*sq,"insert into users (user,firstvisit)" " values ('%s',now())",glocal.cookie); (*sq,"select userid from users where user='%s'" ,glocal.cookie); userid = atoi(row[0]); userid = atoi(row[0]); strcpy (usr_lastvisit,row[1]); websession_setcookie ("docsession",cookie,ti+360*24*60*60); docsession_manage (c,id); } sq = NULL; } }