* BIG rewrite of header handling and slimming of context_loop and session_loop; shuff...
[citadel.git] / webcit / subst.c
index 72659c9b2f351fa948dba0cbe4eaf78039b24f52..6842a99b9b943bdabec2fdd87ac88661bafd5838 100644 (file)
@@ -32,9 +32,11 @@ HashList *Iterators;
 HashList *Conditionals;
 HashList *SortHash;
 
+int DumpTemplateI18NStrings = 0;
 int LoadTemplates = 0;
 int dbg_bactrace_template_errors = 0;
 WCTemplputParams NoCtx;
+StrBuf *I18nDump = NULL;
 
 #define SV_GETTEXT 1
 #define SV_CONDITIONAL 2
@@ -43,6 +45,20 @@ WCTemplputParams NoCtx;
 #define SV_SUBTEMPL 5
 #define SV_PREEVALUATED 6
 
+
+/*
+ * \brief Dynamic content for variable substitution in templates
+ */
+typedef struct _wcsubst {
+       ContextFilter Filter;
+       int wcs_type;                       /* which type of Substitution are we */
+       char wcs_key[32];                   /* copy of our hashkey for debugging */
+       StrBuf *wcs_value;                  /* if we're a string, keep it here */
+       long lvalue;                        /* type long? keep data here */
+       WCHandlerFunc wcs_function; /* funcion hook ???*/
+} wcsubst;
+
+
 typedef struct _WCTemplate {
        StrBuf *Data;
        StrBuf *FileName;
@@ -156,9 +172,14 @@ void LogTemplateError (StrBuf *Target, const char *Type, int ErrorPos, WCTemplpu
                        Type, 
                        ChrPtr(Error));
        }
+/*
        if (Target == NULL) 
                return;
+*/
        WCC = WC;
+       if (WCC == NULL)
+               return;
+
        Header = NewStrBuf();
        if (TP->Tokens != NULL) 
        {
@@ -190,7 +211,7 @@ void LogTemplateError (StrBuf *Target, const char *Type, int ErrorPos, WCTemplpu
                                                      Error,
                                                      eERROR), 1);
 */
-               WildFireSerializePayload(Header, WCC->HBuf, &WCC->nWildfireHeaders, NULL);
+               WildFireSerializePayload(Header, WCC->HBuf, &WCC->Hdr->nWildfireHeaders, NULL);
        }
        else
        {
@@ -207,7 +228,7 @@ void LogTemplateError (StrBuf *Target, const char *Type, int ErrorPos, WCTemplpu
                             ChrPtr(Error), 
                             ChrPtr(TP->Tokens->FlatToken));
                SerializeJson(Header, WildFireException(HKEY(__FILE__), __LINE__, Info, 1), 1);
-               WildFireSerializePayload(Header, WCC->HBuf, &WCC->nWildfireHeaders, NULL);
+               WildFireSerializePayload(Header, WCC->HBuf, &WCC->Hdr->nWildfireHeaders, NULL);
        }
        FreeStrBuf(&Header);
        FreeStrBuf(&Info);
@@ -219,6 +240,45 @@ void LogTemplateError (StrBuf *Target, const char *Type, int ErrorPos, WCTemplpu
 }
 
 
+
+
+void LogError (StrBuf *Target, const char *Type, const char *Format, ...)
+{
+       wcsession *WCC;
+       StrBuf *Header;
+       StrBuf *Error;
+       StrBuf *Info;
+        va_list arg_ptr;
+
+       Info = NewStrBuf();
+       Error = NewStrBuf();
+
+        va_start(arg_ptr, Format);
+       StrBufVAppendPrintf(Error, Format, arg_ptr);
+       va_end(arg_ptr);
+
+       lprintf(1, ChrPtr(Error));
+
+       WCC = WC;
+       Header = NewStrBuf();
+
+
+       SerializeJson(Header, WildFireException(Type, strlen(Type),
+                                               0,
+                                               Info,
+                                               1), 1);
+       WildFireSerializePayload(Header, WCC->HBuf, &WCC->Hdr->nWildfireHeaders, NULL);
+       
+       FreeStrBuf(&Header);
+       FreeStrBuf(&Info);
+       FreeStrBuf(&Error);
+/*
+       if (dbg_bactrace_template_errors)
+               wc_backtrace(); 
+*/
+}
+
+
 void RegisterNS(const char *NSName, 
                long len, 
                int nMinArgs, 
@@ -690,7 +750,8 @@ void pvo_do_cmd(StrBuf *Target, StrBuf *servcmd) {
        }
 }
 
-void GetTemplateTokenString(WCTemplputParams *TP,
+void GetTemplateTokenString(StrBuf *Target, 
+                           WCTemplputParams *TP,
                            int N,
                            const char **Value, 
                            long *len)
@@ -699,8 +760,9 @@ void GetTemplateTokenString(WCTemplputParams *TP,
        WCTemplputParams SubTP;
 
        if (TP->Tokens->nParameters < N) {
-               lprintf(1, "invalid token. this shouldn't have come till here.\n");
-               wc_backtrace(); 
+               LogTemplateError(Target, 
+                                "TokenParameter", N, TP, 
+                                "invalid token %d. this shouldn't have come till here.\n", N);
                *Value = "";
                *len = 0;
                return;
@@ -723,8 +785,15 @@ void GetTemplateTokenString(WCTemplputParams *TP,
                *len = StrLength(Buf);
                break;
        case TYPE_LONG:
+               LogTemplateError(Target, 
+                                "TokenParameter", N, TP, 
+                                "Requesting parameter %d; of type LONG, want string.", N);
+               break;
        case TYPE_PREFINT:
-               break; /* todo: string to text? */
+               LogTemplateError(Target, 
+                                "TokenParameter", N, TP, 
+                                "Requesting parameter %d; of type PREFINT, want string.", N);
+               break;
        case TYPE_GETTEXT:
                *Value = _(TP->Tokens->Params[N]->Start);
                *len = strlen(*Value);
@@ -742,8 +811,60 @@ void GetTemplateTokenString(WCTemplputParams *TP,
                break;
 
        default:
+               LogTemplateError(Target, 
+                                "TokenParameter", N, TP, 
+                                "unknown param type %d; [%d]", N, TP->Tokens->Params[N]->Type);
+               break;
+       }
+}
+
+long GetTemplateTokenNumber(StrBuf *Target, WCTemplputParams *TP, int N, long dflt)
+{
+       long Ret;
+       if (TP->Tokens->nParameters < N) {
+               LogTemplateError(Target, 
+                                "TokenParameter", N, TP, 
+                                "invalid token %d. this shouldn't have come till here.\n", N);
+               wc_backtrace(); 
+               return 0;
+       }
+
+       switch (TP->Tokens->Params[N]->Type) {
+
+       case TYPE_STR:
+               return atol(TP->Tokens->Params[N]->Start);
+               break;
+       case TYPE_BSTR:
+               return  LBstr(TKEY(N));
                break;
-/*/todo log error */
+       case TYPE_PREFSTR:
+               LogTemplateError(Target, 
+                                "TokenParameter", N, TP, 
+                                "requesting a prefstring in param %d want a number", N);
+               if (get_PREF_LONG(TKEY(N), &Ret, dflt))
+                       return Ret;
+               return 0;               
+       case TYPE_LONG:
+               return TP->Tokens->Params[N]->lvalue;
+       case TYPE_PREFINT:
+               if (get_PREF_LONG(TKEY(N), &Ret, dflt))
+                       return Ret;
+               return 0;               
+       case TYPE_GETTEXT:
+               LogTemplateError(Target, 
+                                "TokenParameter", N, TP, 
+                                "requesting a I18N string in param %d; want a number", N);
+               return 0;
+       case TYPE_SUBTEMPLATE:
+               LogTemplateError(Target, 
+                                "TokenParameter", N, TP, 
+                                "requesting a subtemplate in param %d; not supported for numbers", N);
+               return 0;
+       default:
+               LogTemplateError(Target, 
+                                "TokenParameter", N, TP, 
+                                "unknown param type %d; [%d]", N, TP->Tokens->Params[N]->Type);
+               return 0;
        }
 }
 
@@ -899,8 +1020,11 @@ void StrBufAppendTemplate(StrBuf *Target,
                StrEscAppend(Target, Source, NULL, 0, 0);
                break;
        case 'J':
-         StrECMAEscAppend(Target, Source, NULL);
+               StrECMAEscAppend(Target, Source, NULL);
          break;
+       case 'U':
+               StrBufUrlescAppend(Target, Source, NULL);
+               break;
        default:
                StrBufAppendBuf(Target, Source, 0);
        }
@@ -1063,6 +1187,9 @@ TemplateParam *GetNextParameter(StrBuf *Buf, const char **pCh, const char *pe, W
               (*pch == ',' )||
               (*pch == '\n')) pch ++;
 
+       if (DumpTemplateI18NStrings && (Parm->Type == TYPE_GETTEXT)) {
+               StrBufAppendPrintf(I18nDump, "_(\"%s\");\n", Parm->Start);
+       }
        *pCh = pch;
        return Parm;
 }
@@ -1175,6 +1302,9 @@ WCTemplateToken *NewTemplateSubstitute(StrBuf *Buf,
                        NewToken->Flags = 0;
                        break;
                }
+               if (DumpTemplateI18NStrings) {
+                       StrBufAppendPrintf(I18nDump, "_(\"%s\");\n", NewToken->Params[0]->Start);
+               }
                break;
        case SV_SUBTEMPL:
                if (NewToken->nParameters != 1) {
@@ -1250,6 +1380,10 @@ void *prepare_template(StrBuf *filename, StrBuf *Key, HashList *PutThere)
        NewTemplate->nTokensUsed = 0;
        NewTemplate->TokenSpace = 0;
        NewTemplate->Tokens = NULL;
+       NewTemplate->MimeType = NewStrBufPlain(GuessMimeByFilename (SKEY(NewTemplate->FileName)), -1);
+       if (strstr(ChrPtr(NewTemplate->MimeType), "text") != NULL) {
+               StrBufAppendBufPlain(NewTemplate->MimeType, HKEY("; charset=utf-8"), 0);
+       }
 
        Put(PutThere, ChrPtr(Key), StrLength(Key), NewTemplate, FreeWCTemplate);
        return NewTemplate;
@@ -1288,6 +1422,10 @@ void *load_template(StrBuf *filename, StrBuf *Key, HashList *PutThere)
        NewTemplate->TokenSpace = 0;
        NewTemplate->Tokens = NULL;
        NewTemplate->MimeType = NewStrBufPlain(GuessMimeByFilename (SKEY(NewTemplate->FileName)), -1);
+       if (strstr(ChrPtr(NewTemplate->MimeType), "text") != NULL) {
+               StrBufAppendBufPlain(NewTemplate->MimeType, HKEY("; charset=utf-8"), 0);
+       }
+
        if (StrBufReadBLOB(NewTemplate->Data, &fd, 1, statbuf.st_size, &Err) < 0) {
                close(fd);
                FreeWCTemplate(NewTemplate);
@@ -1457,14 +1595,14 @@ int EvaluateToken(StrBuf *Target, int state, WCTemplputParams *TP)
        case SV_CUST_STR_CONDITIONAL: /** Conditional put custom strings from params */
                if (TP->Tokens->nParameters >= 6) {
                        if (EvaluateConditional(Target, 0, state, TP)) {
-                               GetTemplateTokenString(TP, 5, &AppendMe, &AppendMeLen);
+                               GetTemplateTokenString(Target, TP, 5, &AppendMe, &AppendMeLen);
                                StrBufAppendBufPlain(Target, 
                                                     AppendMe, 
                                                     AppendMeLen,
                                                     0);
                        }
                        else{
-                               GetTemplateTokenString(TP, 4, &AppendMe, &AppendMeLen);
+                               GetTemplateTokenString(Target, TP, 4, &AppendMe, &AppendMeLen);
                                StrBufAppendBufPlain(Target, 
                                                     AppendMe, 
                                                     AppendMeLen,
@@ -1672,14 +1810,14 @@ void RegisterITERATOR(const char *Name, long len,
        Put(Iterators, Name, len, It, NULL);
 }
 
-/* typedef struct _iteratestruct {
+typedef struct _iteratestruct {
        int GroupChange;
        int oddeven;
        const char *Key;
        long KeyLen;
        int n;
        int LastN;
-       }IterateStruct; */
+       }IterateStruct; 
 
 void tmpl_iterate_subtmpl(StrBuf *Target, WCTemplputParams *TP)
 {
@@ -1697,6 +1835,10 @@ void tmpl_iterate_subtmpl(StrBuf *Target, WCTemplputParams *TP)
        WCTemplputParams SubTP;
        IterateStruct Status;
 
+       long StartAt = 0;
+       long StepWidth = 0;
+       long StopAt = -1;
+
        memset(&Status, 0, sizeof(IterateStruct));
        memcpy (&SubTP, &TP, sizeof(WCTemplputParams));
        
@@ -1756,21 +1898,37 @@ void tmpl_iterate_subtmpl(StrBuf *Target, WCTemplputParams *TP)
        SubTP.Filter.ContextType = It->ContextType;
        SubTP.Filter.ControlContextType = CTX_ITERATE;
        SubTP.ControlContext = &Status;
-       it = GetNewHashPos(List, 0);
+       
+       if (HAVE_PARAM(2)) {
+               StartAt = GetTemplateTokenNumber(Target, TP, 2, 0);
+       }
+       if (HAVE_PARAM(3)) {
+               StepWidth = GetTemplateTokenNumber(Target, TP, 3, 0);
+       }
+       if (HAVE_PARAM(4)) {
+               StopAt = GetTemplateTokenNumber(Target, TP, 4, -1);
+       }
+       it = GetNewHashPos(List, StepWidth);
+       if (StopAt < 0) {
+               StopAt = GetCount(List);
+       }
        while (GetNextHashPos(List, it, &Status.KeyLen, &Status.Key, &vContext)) {
-               if (DetectGroupChange && Status.n > 0) {
-                       Status.GroupChange = (SortBy->GroupChange(vContext, vLastContext))? 1:0;
-               }
-               Status.LastN = ++Status.LastN == nMembersUsed;
-               SubTP.Context = vContext;
-               if (It->DoSubTemplate != NULL)
-                       It->DoSubTemplate(SubBuf, &SubTP);
-               DoTemplate(TKEY(1), SubBuf, &SubTP);
+               if ((Status.n >= StartAt) && (Status.n <= StopAt)) {
+                       if (DetectGroupChange && Status.n > 0) {
+                               Status.GroupChange = (SortBy->GroupChange(vContext, vLastContext))? 1:0;
+                       }
+                       Status.LastN = (Status.n + 1) == nMembersUsed;
+                       SubTP.Context = vContext;
+                       if (It->DoSubTemplate != NULL)
+                               It->DoSubTemplate(SubBuf, &SubTP);
+                       DoTemplate(TKEY(1), SubBuf, &SubTP);
                        
-               StrBufAppendBuf(Target, SubBuf, 0);
-               FlushStrBuf(SubBuf);
-               Status.oddeven = ! Status.oddeven;
-               vLastContext = vContext;
+                       StrBufAppendBuf(Target, SubBuf, 0);
+                       FlushStrBuf(SubBuf);
+                       Status.oddeven = ! Status.oddeven;
+                       vLastContext = vContext;
+               }
+               Status.n++;
        }
        FreeStrBuf(&SubBuf);
        DeleteHashPos(&it);
@@ -1920,7 +2078,7 @@ int ConditionalContextStr(StrBuf *Target, WCTemplputParams *TP)
        const char *CompareToken;
        long len;
 
-       GetTemplateTokenString(TP, 2, &CompareToken, &len);
+       GetTemplateTokenString(Target, TP, 2, &CompareToken, &len);
        return strcmp(ChrPtr(TokenText), CompareToken) == 0;
 }
 
@@ -1941,7 +2099,8 @@ void tmpl_do_boxed(StrBuf *Target, WCTemplputParams *TP)
                else {
                        const char *Ch;
                        long len;
-                       GetTemplateTokenString(TP, 
+                       GetTemplateTokenString(Target, 
+                                              TP, 
                                               1,
                                               &Ch,
                                               &len);
@@ -1978,7 +2137,8 @@ void tmpl_do_tabbed(StrBuf *Target, WCTemplputParams *TP)
                else if (TP->Tokens->Params[i * 2]->Type == TYPE_GETTEXT) {
                        const char *Ch;
                        long len;
-                       GetTemplateTokenString(TP, 
+                       GetTemplateTokenString(Target, 
+                                              TP, 
                                               i * 2,
                                               &Ch,
                                               &len);
@@ -2374,4 +2534,74 @@ InitModule_SUBST
        RegisterControlNS(HKEY("ITERATE:N"), 0, 0, tmplput_ITERATE_LASTN, CTX_ITERATE);
 }
 
+void
+ServerStartModule_SUBST
+(void)
+{
+       WirelessTemplateCache = NewHash(1, NULL);
+       WirelessLocalTemplateCache = NewHash(1, NULL);
+       LocalTemplateCache = NewHash(1, NULL);
+       TemplateCache = NewHash(1, NULL);
+
+       GlobalNS = NewHash(1, NULL);
+       Iterators = NewHash(1, NULL);
+       Conditionals = NewHash(1, NULL);
+       SortHash = NewHash(1, NULL);
+}
+
+void
+FinalizeModule_SUBST
+(void)
+{
+
+}
+
+void 
+ServerShutdownModule_SUBST
+(void)
+{
+       DeleteHash(&WirelessTemplateCache);
+       DeleteHash(&WirelessLocalTemplateCache);
+       DeleteHash(&TemplateCache);
+       DeleteHash(&LocalTemplateCache);
+
+       DeleteHash(&GlobalNS);
+       DeleteHash(&Iterators);
+       DeleteHash(&Conditionals);
+       DeleteHash(&SortHash);
+
+}
+
+
+void
+SessionNewModule_SUBST
+(wcsession *sess)
+{
+
+}
+
+void
+SessionAttachModule_SUBST
+(wcsession *sess)
+{
+       sess->vars = NewHash(1,NULL);
+}
+
+void
+SessionDetachModule_SUBST
+(wcsession *sess)
+{
+       DeleteHash(&sess->vars);
+}
+
+void 
+SessionDestroyModule_SUBST  
+(wcsession *sess)
+{
+
+}
+
+
+
+
 /*@}*/