]> code.citadel.org Git - citadel.git/blobdiff - webcit/subst.c
* hm, something is going wrong here. allocing bigger spaces here for filenames fixes...
[citadel.git] / webcit / subst.c
index a4a8edea2d7f601b82fa2ab94a80b925c00b39ae..ca2a6975bf4a1f14c0fac585ddb2e1534a5a43c6 100644 (file)
@@ -1,14 +1,19 @@
 /*
  * $Id$
  */
-
 #include "sysdep.h"
+
+
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <unistd.h>
 #include <dirent.h>
 #include <errno.h>
+
+#include <unistd.h>
+#include <stdio.h>
 #include <stdarg.h>
+#include <stddef.h>
+
 #define SHOW_ME_VAPPEND_PRINTF
 
 #include "webcit.h"
@@ -25,6 +30,7 @@ HashList *GlobalNS;
 HashList *Iterators;
 HashList *Conditionals;
 HashList *SortHash;
+HashList *Defines;
 
 int DumpTemplateI18NStrings = 0;
 int LoadTemplates = 0;
@@ -780,6 +786,7 @@ void GetTemplateTokenString(StrBuf *Target,
 
        switch (TP->Tokens->Params[N]->Type) {
 
+       case TYPE_INTDEFINE:
        case TYPE_STR:
                *Value = TP->Tokens->Params[N]->Start;
                *len = TP->Tokens->Params[N]->len;
@@ -890,7 +897,8 @@ long GetTemplateTokenNumber(StrBuf *Target, WCTemplputParams *TP, int N, long df
                }
                if (get_PREF_LONG(TKEY(N), &Ret, dflt))
                        return Ret;
-               return 0;               
+               return 0;
+       case TYPE_INTDEFINE:
        case TYPE_LONG:
                return TP->Tokens->Params[N]->lvalue;
        case TYPE_PREFINT:
@@ -1111,7 +1119,12 @@ void PutNewToken(WCTemplate *Template, WCTemplateToken *NewToken)
        Template->Tokens[(Template->nTokensUsed)++] = NewToken;
 }
 
-TemplateParam *GetNextParameter(StrBuf *Buf, const char **pCh, const char *pe, WCTemplateToken *Tokens, WCTemplate *pTmpl)
+TemplateParam *GetNextParameter(StrBuf *Buf, 
+                               const char **pCh, 
+                               const char *pe, 
+                               WCTemplateToken *Tokens, 
+                               WCTemplate *pTmpl, 
+                               WCTemplputParams *TP)
 {
        const char *pch = *pCh;
        const char *pchs, *pche;
@@ -1145,6 +1158,10 @@ TemplateParam *GetNextParameter(StrBuf *Buf, const char **pCh, const char *pe, W
                        ParamBrace = 1;
                }
        }
+       else if (*pch == '#') {
+               Parm->Type = TYPE_INTDEFINE;
+               pch ++;
+       }
        else if (*pch == '_') {
                Parm->Type = TYPE_GETTEXT;
                pch ++;
@@ -1249,6 +1266,25 @@ TemplateParam *GetNextParameter(StrBuf *Buf, const char **pCh, const char *pe, W
        if (DumpTemplateI18NStrings && (Parm->Type == TYPE_GETTEXT)) {
                StrBufAppendPrintf(I18nDump, "_(\"%s\");\n", Parm->Start);
        }
+       if (Parm->Type == TYPE_INTDEFINE)
+       {
+               void *vPVal;
+
+               if (GetHash(Defines, Parm->Start, Parm->len, &vPVal) &&
+                   (vPVal != NULL))
+               {
+                       long *PVal;
+                       PVal = (long*) vPVal;
+               
+                       Parm->lvalue = *PVal;
+               }
+               else 
+               {
+                       LogTemplateError(NULL, "Define", ERR_PARM1, TP,
+                                        "%s isn't known!!",
+                                        Parm->Start);
+               }
+       }
        *pCh = pch;
        return Parm;
 }
@@ -1299,7 +1335,7 @@ WCTemplateToken *NewTemplateSubstitute(StrBuf *Buf,
                                        "Warning, Non welformed Token; missing right parenthesis");
                        }
                        while (pch < pTmplEnd - 1) {
-                               Param = GetNextParameter(Buf, &pch, pTmplEnd - 1, NewToken, pTmpl);
+                               Param = GetNextParameter(Buf, &pch, pTmplEnd - 1, NewToken, pTmpl, &TP);
                                if (Param != NULL) {
                                        NewToken->HaveParameters = 1;
                                        if (NewToken->nParameters > MAXPARAM) {
@@ -1384,7 +1420,7 @@ WCTemplateToken *NewTemplateSubstitute(StrBuf *Buf,
        case SV_NEG_CONDITIONAL:
                if (NewToken->nParameters <2) {
                        LogTemplateError(
-                               NULL, "Conditional", ERR_NAME, &TP,
+                               NULL, "Conditional", ERR_PARM1, &TP,
                                "require at least 2 parameters, you gave %d params", 
                                NewToken->nParameters);
                        NewToken->Flags = 0;
@@ -1392,7 +1428,7 @@ WCTemplateToken *NewTemplateSubstitute(StrBuf *Buf,
                }
                if (NewToken->Params[1]->lvalue == 0) {
                        LogTemplateError(
-                               NULL, "Conditional", ERR_NAME, &TP,
+                               NULL, "Conditional", ERR_PARM1, &TP,
                                "Conditional ID (Parameter 1) mustn't be 0!");
                        NewToken->Flags = 0;
                        break;
@@ -1406,7 +1442,7 @@ WCTemplateToken *NewTemplateSubstitute(StrBuf *Buf,
                            (NewToken->Params[0]->Start[0] == 'X'))
                                break;
                        LogTemplateError(
-                               NULL, "Conditional", ERR_NAME, &TP,
+                               NULL, "Conditional", ERR_PARM1, &TP,
                                "Not found!");
 /*
                        NewToken->Error = NewStrBuf();
@@ -1561,74 +1597,185 @@ const char* PrintTemplate(void *vSubst)
 
 }
 
-int LoadTemplateDir(const char *DirName, HashList *wireless, HashList *big)
+int LoadTemplateDir(const StrBuf *DirName, HashList *wireless, HashList *big, const StrBuf *BaseKey)
 {
+       int Toplevel;
        StrBuf *FileName;
-       StrBuf *Tag;
-       StrBuf *Dir;
+       StrBuf *Key;
+       StrBuf *SubKey;
+       StrBuf *SubDirectory;
        DIR *filedir = NULL;
        struct dirent *filedir_entry;
+       struct dirent *d;
+       int d_type = 0;
        int d_namelen;
        int d_without_ext;
        int IsMobile;
        
-       Dir = NewStrBuf();
-       StrBufPrintf(Dir, "%s/t", DirName);
-       filedir = opendir (ChrPtr(Dir));
+       d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 1);
+       if (d == NULL) {
+               return 0;
+       }
+
+       filedir = opendir (ChrPtr(DirName));
        if (filedir == NULL) {
-               FreeStrBuf(&Dir);
+               free(d);
                return 0;
        }
 
-       FileName = NewStrBuf();
-       Tag = NewStrBuf();
-       while ((filedir_entry = readdir(filedir)))
+       Toplevel = StrLength(BaseKey) == 0;
+       SubDirectory = NewStrBuf();
+       SubKey = NewStrBuf();
+       FileName = NewStrBufPlain(NULL, PATH_MAX);
+       Key = NewStrBuf();
+       while ((readdir_r(filedir, d, &filedir_entry) == 0) &&
+              (filedir_entry != NULL))
        {
                char *MinorPtr;
                char *PStart;
 #ifdef _DIRENT_HAVE_D_NAMELEN
                d_namelen = filedir_entry->d_namelen;
+               d_type = filedir_entry->d_type;
 #else
+
+#ifndef DT_UNKNOWN
+#define DT_UNKNOWN     0
+#define DT_DIR         4
+#define DT_REG         8
+#define DT_LNK         10
+
+#define IFTODT(mode)   (((mode) & 0170000) >> 12)
+#define DTTOIF(dirtype)        ((dirtype) << 12)
+#endif
                d_namelen = strlen(filedir_entry->d_name);
+               d_type = DT_UNKNOWN;
 #endif
                d_without_ext = d_namelen;
-               while ((d_without_ext > 0) && (filedir_entry->d_name[d_without_ext] != '.'))
-                       d_without_ext --;
-               if ((d_without_ext == 0) || (d_namelen < 3))
-                       continue;
+
                if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
                        continue; /* Ignore backup files... */
 
-               IsMobile = (strstr(filedir_entry->d_name, ".m.html")!= NULL);
-               PStart = filedir_entry->d_name;
-               StrBufPrintf(FileName, "%s/%s", ChrPtr(Dir),  filedir_entry->d_name);
-               MinorPtr = strchr(filedir_entry->d_name, '.');
-               if (MinorPtr != NULL)
-                       *MinorPtr = '\0';
-               StrBufPlain(Tag, filedir_entry->d_name, MinorPtr - filedir_entry->d_name);
+               if ((d_namelen == 1) && 
+                   (filedir_entry->d_name[0] == '.'))
+                       continue;
 
-               if (LoadTemplates > 1)
-                       lprintf(1, "%s %d %s\n",ChrPtr(FileName), IsMobile, ChrPtr(Tag));
-               if (LoadTemplates == 0)
-                       load_template(FileName, Tag, (IsMobile)?wireless:big);
-               else
-                       prepare_template(FileName, Tag, (IsMobile)?wireless:big);
+               if ((d_namelen == 2) && 
+                   (filedir_entry->d_name[0] == '.') &&
+                   (filedir_entry->d_name[1] == '.'))
+                       continue;
+
+               if (d_type == DT_UNKNOWN) {
+                       struct stat s;
+                       char path[PATH_MAX];
+                       snprintf(path, PATH_MAX, "%s/%s", 
+                                ChrPtr(DirName), filedir_entry->d_name);
+                       if (stat(path, &s) == 0) {
+                               d_type = IFTODT(s.st_mode);
+                       }
+               }
+               switch (d_type)
+               {
+               case DT_DIR:
+                       /* Skip directories we are not interested in... */
+                       if (strcmp(filedir_entry->d_name, ".svn") == 0)
+                               break;
+
+                       FlushStrBuf(SubKey);
+                       if (!Toplevel) {
+                               /* If we're not toplevel, the upper dirs count as foo_bar_<local name>*/
+                               StrBufAppendBuf(SubKey, BaseKey, 0);
+                               StrBufAppendBufPlain(SubKey, HKEY("_"), 0);
+                       }
+                       StrBufAppendBufPlain(SubKey, filedir_entry->d_name, d_namelen, 0);
+
+                       FlushStrBuf(SubDirectory);
+                       StrBufAppendBuf(SubDirectory, DirName, 0);
+                       if (ChrPtr(SubDirectory)[StrLength(SubDirectory) - 1] != '/')
+                               StrBufAppendBufPlain(SubDirectory, HKEY("/"), 0);
+                       StrBufAppendBufPlain(SubDirectory, filedir_entry->d_name, d_namelen, 0);
+
+                       LoadTemplateDir(SubDirectory, wireless, big, SubKey);
+
+                       break;
+               case DT_LNK: /* TODO: check whether its a file or a directory */
+               case DT_REG:
+
+
+                       while ((d_without_ext > 0) && (filedir_entry->d_name[d_without_ext] != '.'))
+                               d_without_ext --;
+                       if ((d_without_ext == 0) || (d_namelen < 3))
+                               continue;
+                       if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
+                               continue; /* Ignore backup files... */
+                       /* .m.xxx is for mobile useragents! */
+                       if (d_without_ext > 2)
+                               IsMobile = (filedir_entry->d_name[d_without_ext - 1] == 'm') &&
+                                       (filedir_entry->d_name[d_without_ext - 2] == '.');
+                       PStart = filedir_entry->d_name;
+                       StrBufPrintf(FileName, "%s/%s", ChrPtr(DirName),  filedir_entry->d_name);
+                       MinorPtr = strchr(filedir_entry->d_name, '.');
+                       if (MinorPtr != NULL)
+                               *MinorPtr = '\0';
+                       FlushStrBuf(Key);
+                       if (!Toplevel) {
+                               /* If we're not toplevel, the upper dirs count as foo_bar_<local name>*/
+                               StrBufAppendBuf(Key, BaseKey, 0);
+                               StrBufAppendBufPlain(Key, HKEY("_"), 0);
+                       }
+                       StrBufAppendBufPlain(Key, filedir_entry->d_name, MinorPtr - filedir_entry->d_name, 0);
+
+                       if (LoadTemplates >= 1)
+                               lprintf(1, "%s %d %s\n", ChrPtr(FileName), IsMobile, ChrPtr(Key));
+                       if (LoadTemplates == 0)
+                               load_template(FileName, Key, (IsMobile)?wireless:big);
+                       else
+                               prepare_template(FileName, Key, (IsMobile)?wireless:big);
+               default:
+                       break;
+               }
        }
+       free(d);
        closedir(filedir);
        FreeStrBuf(&FileName);
-       FreeStrBuf(&Tag);
-       FreeStrBuf(&Dir);
+       FreeStrBuf(&Key);
+       FreeStrBuf(&SubDirectory);
+       FreeStrBuf(&SubKey);
        return 1;
 }
 
 void InitTemplateCache(void)
 {
-       LoadTemplateDir(static_dirs[0],
+       StrBuf *Key;
+       StrBuf *Dir;
+
+       Dir = NewStrBuf();
+       Key = NewStrBuf();
+
+       /* Primary Template set... */
+       StrBufPrintf(Dir, "%s/t", static_dirs[0]);
+       LoadTemplateDir(Dir,
                        WirelessTemplateCache,
-                       TemplateCache);
-       LoadTemplateDir(static_dirs[1],
+                       TemplateCache, 
+                       Key);
+
+       /* User local Template set */
+       StrBufPrintf(Dir, "%s/t", static_dirs[1]);
+       LoadTemplateDir(Dir,
                        WirelessLocalTemplateCache,
-                       LocalTemplateCache);
+                       LocalTemplateCache, 
+                       Key);
+       
+       /* Debug Templates, just to be loaded while debugging. */
+       
+       StrBufPrintf(Dir, "%s/dbg", static_dirs[0]);
+       LoadTemplateDir(Dir,
+                       WirelessTemplateCache,
+                       TemplateCache, 
+                       Key);
+
+
+       FreeStrBuf(&Dir);
+       FreeStrBuf(&Key);
 }
 
 
@@ -1814,7 +1961,7 @@ const StrBuf *DoTemplate(const char *templatename, long len, StrBuf *Target, WCT
                TP = &LocalTP;
        }
 
-       if (WC->is_mobile) {
+       if (WC->is_mobile > 0) {
                Static = WirelessTemplateCache;
                StaticLocal = WirelessLocalTemplateCache;
        }
@@ -1907,7 +2054,7 @@ int preeval_iterate(WCTemplateToken *Token)
        TP->Tokens = Token;
        if (!GetHash(Iterators, TKEY(0), &vIt)) {
                LogTemplateError(
-                       NULL, "Iterator", ERR_NAME, TP,
+                       NULL, "Iterator", ERR_PARM1, TP,
                        "not found");
                return 0;
        }
@@ -2174,6 +2321,18 @@ void RegisterControlConditional(const char *Name, long len,
        Put(Conditionals, Name, len, Cond, NULL);
 }
 
+void RegisterTokenParamDefine(const char *Name, long len, 
+                             long Value)
+{
+       long *PVal;
+
+       PVal = (long*)malloc(sizeof(long));
+       *PVal = Value;
+       Put(Defines, Name, len, PVal, NULL);
+}
+
+HashList *Defines;
+
 /*-----------------------------------------------------------------------------
  *                      Context Strings
  */
@@ -2199,7 +2358,7 @@ void tmpl_do_boxed(StrBuf *Target, WCTemplputParams *TP)
 {
        WCTemplputParams SubTP;
 
-       StrBuf *Headline;
+       StrBuf *Headline = NULL;
        if (TP->Tokens->nParameters == 2) {
                if (TP->Tokens->Params[1]->Type == TYPE_STR) {
                        Headline = NewStrBuf();
@@ -2216,6 +2375,7 @@ void tmpl_do_boxed(StrBuf *Target, WCTemplputParams *TP)
                        Headline = NewStrBufPlain(Ch, len);
                }
        }
+       /* else TODO error? logging? */
        memcpy (&SubTP, TP, sizeof(WCTemplputParams));
        SubTP.Context = Headline;
        SubTP.Filter.ContextType = CTX_STRBUF;
@@ -2294,6 +2454,11 @@ void RegisterSortFunc(const char *name, long len,
        NewSort->Reverse = Reverse;
        NewSort->GroupChange = GroupChange;
        NewSort->ContextType = ContextType;
+       if (ContextType == CTX_NONE) {
+               lprintf(1, "sorting requires a context. CTX_NONE won't make it.\n");
+               exit(1);
+       }
+               
        Put(SortHash, name, len, NewSort, DestroySortStruct);
 }
 
@@ -2346,6 +2511,9 @@ CompareFunc RetrieveSort(WCTemplputParams *TP,
        }
        SortBy = (SortStruct*)vSortBy;
 
+       if (SortBy->ContextType != TP->Filter.ContextType)
+               return NULL;
+
        /** Ok, its us, lets see in which direction we should sort... */
        if (havebstr("SortOrder")) {
                SortOrder = LBSTR("SortOrder");
@@ -2673,6 +2841,7 @@ ServerStartModule_SUBST
        Iterators = NewHash(1, NULL);
        Conditionals = NewHash(1, NULL);
        SortHash = NewHash(1, NULL);
+       Defines = NewHash(1, NULL);
 }
 
 void
@@ -2695,7 +2864,7 @@ ServerShutdownModule_SUBST
        DeleteHash(&Iterators);
        DeleteHash(&Conditionals);
        DeleteHash(&SortHash);
-
+       DeleteHash(&Defines);
 }