|
588bb7c…
|
aku
|
1 |
/* |
|
c19f34c…
|
drh
|
2 |
** Copyright (c) 2008 D. Richard Hipp |
|
588bb7c…
|
aku
|
3 |
** |
|
588bb7c…
|
aku
|
4 |
** This program is free software; you can redistribute it and/or |
|
c06edd2…
|
drh
|
5 |
** modify it under the terms of the Simplified BSD License (also |
|
c06edd2…
|
drh
|
6 |
** known as the "2-Clause License" or "FreeBSD License".) |
|
c06edd2…
|
drh
|
7 |
|
|
588bb7c…
|
aku
|
8 |
** This program is distributed in the hope that it will be useful, |
|
c06edd2…
|
drh
|
9 |
** but without any warranty; without even the implied warranty of |
|
c06edd2…
|
drh
|
10 |
** merchantability or fitness for a particular purpose. |
|
588bb7c…
|
aku
|
11 |
** |
|
588bb7c…
|
aku
|
12 |
** Author contact information: |
|
588bb7c…
|
aku
|
13 |
** [email protected] |
|
588bb7c…
|
aku
|
14 |
** http://www.hwaci.com/drh/ |
|
588bb7c…
|
aku
|
15 |
** |
|
588bb7c…
|
aku
|
16 |
******************************************************************************* |
|
588bb7c…
|
aku
|
17 |
** |
|
588bb7c…
|
aku
|
18 |
** This file contains an interface between the TH scripting language |
|
588bb7c…
|
aku
|
19 |
** (an independent project) and fossil. |
|
588bb7c…
|
aku
|
20 |
*/ |
|
588bb7c…
|
aku
|
21 |
#include "config.h" |
|
588bb7c…
|
aku
|
22 |
#include "th_main.h" |
|
4f8c897…
|
drh
|
23 |
#include "sqlite3.h" |
|
588bb7c…
|
aku
|
24 |
|
|
0e68620…
|
mistachkin
|
25 |
#if INTERFACE |
|
0e68620…
|
mistachkin
|
26 |
/* |
|
0e68620…
|
mistachkin
|
27 |
** Flag parameters to the Th_FossilInit() routine used to control the |
|
0e68620…
|
mistachkin
|
28 |
** interpreter creation and initialization process. |
|
0e68620…
|
mistachkin
|
29 |
*/ |
|
0e68620…
|
mistachkin
|
30 |
#define TH_INIT_NONE ((u32)0x00000000) /* No flags. */ |
|
0e68620…
|
mistachkin
|
31 |
#define TH_INIT_NEED_CONFIG ((u32)0x00000001) /* Open configuration first? */ |
|
0e68620…
|
mistachkin
|
32 |
#define TH_INIT_FORCE_TCL ((u32)0x00000002) /* Force Tcl to be enabled? */ |
|
a17919a…
|
mistachkin
|
33 |
#define TH_INIT_FORCE_RESET ((u32)0x00000004) /* Force TH1 commands re-added? */ |
|
0e68620…
|
mistachkin
|
34 |
#define TH_INIT_FORCE_SETUP ((u32)0x00000008) /* Force eval of setup script? */ |
|
57d8a71…
|
mistachkin
|
35 |
#define TH_INIT_NO_REPO ((u32)0x00000010) /* Skip opening repository. */ |
|
9164a5d…
|
drh
|
36 |
#define TH_INIT_MASK ((u32)0x0000001F) /* All possible init flags. */ |
|
3355835…
|
mistachkin
|
37 |
|
|
3355835…
|
mistachkin
|
38 |
/* |
|
3355835…
|
mistachkin
|
39 |
** Useful and/or "well-known" combinations of flag values. |
|
3355835…
|
mistachkin
|
40 |
*/ |
|
3355835…
|
mistachkin
|
41 |
#define TH_INIT_DEFAULT (TH_INIT_NONE) /* Default flags. */ |
|
1c528d3…
|
mistachkin
|
42 |
#define TH_INIT_HOOK (TH_INIT_NEED_CONFIG | TH_INIT_FORCE_SETUP) |
|
3355835…
|
mistachkin
|
43 |
#define TH_INIT_FORBID_MASK (TH_INIT_FORCE_TCL) /* Illegal from a script. */ |
|
1c528d3…
|
mistachkin
|
44 |
#endif |
|
142200b…
|
mistachkin
|
45 |
|
|
142200b…
|
mistachkin
|
46 |
/* |
|
142200b…
|
mistachkin
|
47 |
** Flags set by functions in this file to keep track of integration state |
|
142200b…
|
mistachkin
|
48 |
** information. These flags should not be used outside of this file. |
|
142200b…
|
mistachkin
|
49 |
*/ |
|
a5f00e0…
|
stephan
|
50 |
#define TH_STATE_CONFIG ((u32)0x00000200) /* We opened the config. */ |
|
a5f00e0…
|
stephan
|
51 |
#define TH_STATE_REPOSITORY ((u32)0x00000400) /* We opened the repository. */ |
|
a5f00e0…
|
stephan
|
52 |
#define TH_STATE_MASK ((u32)0x00000600) /* All possible state flags. */ |
|
1c528d3…
|
mistachkin
|
53 |
|
|
1c528d3…
|
mistachkin
|
54 |
#ifdef FOSSIL_ENABLE_TH1_HOOKS |
|
1c528d3…
|
mistachkin
|
55 |
/* |
|
1c528d3…
|
mistachkin
|
56 |
** These are the "well-known" TH1 error messages that occur when no hook is |
|
1c528d3…
|
mistachkin
|
57 |
** registered to be called prior to executing a command or processing a web |
|
1c528d3…
|
mistachkin
|
58 |
** page, respectively. If one of these errors is seen, it will not be sent |
|
1c528d3…
|
mistachkin
|
59 |
** or displayed to the remote user or local interactive user, respectively. |
|
1c528d3…
|
mistachkin
|
60 |
*/ |
|
1c528d3…
|
mistachkin
|
61 |
#define NO_COMMAND_HOOK_ERROR "no such command: command_hook" |
|
1c528d3…
|
mistachkin
|
62 |
#define NO_WEBPAGE_HOOK_ERROR "no such command: webpage_hook" |
|
0e68620…
|
mistachkin
|
63 |
#endif |
|
0e68620…
|
mistachkin
|
64 |
|
|
1c528d3…
|
mistachkin
|
65 |
/* |
|
b727218…
|
drh
|
66 |
** These macros are used within this file to detect if the repository and |
|
b727218…
|
drh
|
67 |
** configuration ("user") database are currently open. |
|
b727218…
|
drh
|
68 |
*/ |
|
b727218…
|
drh
|
69 |
#define Th_IsRepositoryOpen() (g.repositoryOpen) |
|
b727218…
|
drh
|
70 |
#define Th_IsConfigOpen() (g.zConfigDbName!=0) |
|
b727218…
|
drh
|
71 |
|
|
999e33c…
|
mistachkin
|
72 |
/* |
|
999e33c…
|
mistachkin
|
73 |
** When memory debugging is enabled, use our custom memory allocator. |
|
999e33c…
|
mistachkin
|
74 |
*/ |
|
999e33c…
|
mistachkin
|
75 |
#if defined(TH_MEMDEBUG) |
|
999e33c…
|
mistachkin
|
76 |
/* |
|
999e33c…
|
mistachkin
|
77 |
** Global variable counting the number of outstanding calls to malloc() |
|
999e33c…
|
mistachkin
|
78 |
** made by the th1 implementation. This is used to catch memory leaks |
|
e2bdc10…
|
danield
|
79 |
** in the interpreter. Obviously, it also means th1 is not thread-safe. |
|
999e33c…
|
mistachkin
|
80 |
*/ |
|
999e33c…
|
mistachkin
|
81 |
static int nOutstandingMalloc = 0; |
|
999e33c…
|
mistachkin
|
82 |
|
|
999e33c…
|
mistachkin
|
83 |
/* |
|
999e33c…
|
mistachkin
|
84 |
** Implementations of malloc() and free() to pass to the interpreter. |
|
999e33c…
|
mistachkin
|
85 |
*/ |
|
999e33c…
|
mistachkin
|
86 |
static void *xMalloc(unsigned int n){ |
|
999e33c…
|
mistachkin
|
87 |
void *p = fossil_malloc(n); |
|
999e33c…
|
mistachkin
|
88 |
if( p ){ |
|
999e33c…
|
mistachkin
|
89 |
nOutstandingMalloc++; |
|
999e33c…
|
mistachkin
|
90 |
} |
|
999e33c…
|
mistachkin
|
91 |
return p; |
|
999e33c…
|
mistachkin
|
92 |
} |
|
999e33c…
|
mistachkin
|
93 |
static void xFree(void *p){ |
|
999e33c…
|
mistachkin
|
94 |
if( p ){ |
|
999e33c…
|
mistachkin
|
95 |
nOutstandingMalloc--; |
|
999e33c…
|
mistachkin
|
96 |
} |
|
999e33c…
|
mistachkin
|
97 |
free(p); |
|
999e33c…
|
mistachkin
|
98 |
} |
|
999e33c…
|
mistachkin
|
99 |
static Th_Vtab vtab = { xMalloc, xFree }; |
|
999e33c…
|
mistachkin
|
100 |
|
|
999e33c…
|
mistachkin
|
101 |
/* |
|
999e33c…
|
mistachkin
|
102 |
** Returns the number of outstanding TH1 memory allocations. |
|
999e33c…
|
mistachkin
|
103 |
*/ |
|
999e33c…
|
mistachkin
|
104 |
int Th_GetOutstandingMalloc(){ |
|
999e33c…
|
mistachkin
|
105 |
return nOutstandingMalloc; |
|
999e33c…
|
mistachkin
|
106 |
} |
|
999e33c…
|
mistachkin
|
107 |
#endif |
|
60acb31…
|
mistachkin
|
108 |
|
|
60acb31…
|
mistachkin
|
109 |
/* |
|
f55c6a1…
|
drh
|
110 |
** Generate a TH1 trace message if debugging is enabled. |
|
f55c6a1…
|
drh
|
111 |
*/ |
|
f55c6a1…
|
drh
|
112 |
void Th_Trace(const char *zFormat, ...){ |
|
f55c6a1…
|
drh
|
113 |
va_list ap; |
|
f55c6a1…
|
drh
|
114 |
va_start(ap, zFormat); |
|
f55c6a1…
|
drh
|
115 |
blob_vappendf(&g.thLog, zFormat, ap); |
|
f55c6a1…
|
drh
|
116 |
va_end(ap); |
|
f55c6a1…
|
drh
|
117 |
} |
|
f55c6a1…
|
drh
|
118 |
|
|
0264475…
|
mistachkin
|
119 |
/* |
|
c1915c3…
|
mistachkin
|
120 |
** Forces input and output to be done via the CGI subsystem. |
|
c1915c3…
|
mistachkin
|
121 |
*/ |
|
c1915c3…
|
mistachkin
|
122 |
void Th_ForceCgi(int fullHttpReply){ |
|
c1915c3…
|
mistachkin
|
123 |
g.httpOut = stdout; |
|
c1915c3…
|
mistachkin
|
124 |
g.httpIn = stdin; |
|
c1915c3…
|
mistachkin
|
125 |
fossil_binary_mode(g.httpOut); |
|
c1915c3…
|
mistachkin
|
126 |
fossil_binary_mode(g.httpIn); |
|
c1915c3…
|
mistachkin
|
127 |
g.cgiOutput = 1; |
|
c1915c3…
|
mistachkin
|
128 |
g.fullHttpReply = fullHttpReply; |
|
c1915c3…
|
mistachkin
|
129 |
} |
|
c1915c3…
|
mistachkin
|
130 |
|
|
c1915c3…
|
mistachkin
|
131 |
/* |
|
0264475…
|
mistachkin
|
132 |
** Checks if the TH1 trace log needs to be enabled. If so, prepares |
|
0264475…
|
mistachkin
|
133 |
** it for use. |
|
0264475…
|
mistachkin
|
134 |
*/ |
|
0264475…
|
mistachkin
|
135 |
void Th_InitTraceLog(){ |
|
0264475…
|
mistachkin
|
136 |
g.thTrace = find_option("th-trace", 0, 0)!=0; |
|
0264475…
|
mistachkin
|
137 |
if( g.thTrace ){ |
|
a588e55…
|
mistachkin
|
138 |
g.fAnyTrace = 1; |
|
0264475…
|
mistachkin
|
139 |
blob_zero(&g.thLog); |
|
0264475…
|
mistachkin
|
140 |
} |
|
0264475…
|
mistachkin
|
141 |
} |
|
0264475…
|
mistachkin
|
142 |
|
|
0264475…
|
mistachkin
|
143 |
/* |
|
0264475…
|
mistachkin
|
144 |
** Prints the entire contents of the TH1 trace log to the standard |
|
0264475…
|
mistachkin
|
145 |
** output channel. |
|
0264475…
|
mistachkin
|
146 |
*/ |
|
0264475…
|
mistachkin
|
147 |
void Th_PrintTraceLog(){ |
|
0264475…
|
mistachkin
|
148 |
if( g.thTrace ){ |
|
0264475…
|
mistachkin
|
149 |
fossil_print("\n------------------ BEGIN TRACE LOG ------------------\n"); |
|
0264475…
|
mistachkin
|
150 |
fossil_print("%s", blob_str(&g.thLog)); |
|
0264475…
|
mistachkin
|
151 |
fossil_print("\n------------------- END TRACE LOG -------------------\n"); |
|
f4ceace…
|
mistachkin
|
152 |
} |
|
f4ceace…
|
mistachkin
|
153 |
} |
|
f4ceace…
|
mistachkin
|
154 |
|
|
f4ceace…
|
mistachkin
|
155 |
/* |
|
f677d53…
|
danield
|
156 |
** - adapted from ls_cmd_rev in checkin.c |
|
f677d53…
|
danield
|
157 |
** - adapted commands/error handling for usage within th1 |
|
f677d53…
|
danield
|
158 |
** - interface adapted to allow result creation as TH1 List |
|
f4ceace…
|
mistachkin
|
159 |
** |
|
bc36fdc…
|
danield
|
160 |
** Takes a check-in identifier in zRev and an optiona glob pattern in zGLOB |
|
f4ceace…
|
mistachkin
|
161 |
** as parameter returns a TH list in pzList,pnList with filenames matching |
|
f4ceace…
|
mistachkin
|
162 |
** glob pattern with the checking |
|
f4ceace…
|
mistachkin
|
163 |
*/ |
|
f4ceace…
|
mistachkin
|
164 |
static void dir_cmd_rev( |
|
f4ceace…
|
mistachkin
|
165 |
Th_Interp *interp, |
|
f4ceace…
|
mistachkin
|
166 |
char **pzList, |
|
f4ceace…
|
mistachkin
|
167 |
int *pnList, |
|
f4ceace…
|
mistachkin
|
168 |
const char *zRev, /* Revision string given */ |
|
f4ceace…
|
mistachkin
|
169 |
const char *zGlob, /* Glob pattern given */ |
|
f4ceace…
|
mistachkin
|
170 |
int bDetails |
|
f4ceace…
|
mistachkin
|
171 |
){ |
|
f4ceace…
|
mistachkin
|
172 |
Stmt q; |
|
f4ceace…
|
mistachkin
|
173 |
char *zOrderBy = "pathname COLLATE nocase"; |
|
f4ceace…
|
mistachkin
|
174 |
int rid; |
|
f4ceace…
|
mistachkin
|
175 |
|
|
f4ceace…
|
mistachkin
|
176 |
rid = th1_name_to_typed_rid(interp, zRev, "ci"); |
|
f4ceace…
|
mistachkin
|
177 |
compute_fileage(rid, zGlob); |
|
f4ceace…
|
mistachkin
|
178 |
db_prepare(&q, |
|
ea63a2d…
|
drh
|
179 |
"SELECT datetime(fileage.mtime, toLocal()), fileage.pathname,\n" |
|
f4ceace…
|
mistachkin
|
180 |
" blob.size\n" |
|
f4ceace…
|
mistachkin
|
181 |
" FROM fileage, blob\n" |
|
f4ceace…
|
mistachkin
|
182 |
" WHERE blob.rid=fileage.fid \n" |
|
f4ceace…
|
mistachkin
|
183 |
" ORDER BY %s;", zOrderBy /*safe-for-%s*/ |
|
f4ceace…
|
mistachkin
|
184 |
); |
|
f4ceace…
|
mistachkin
|
185 |
while( db_step(&q)==SQLITE_ROW ){ |
|
f4ceace…
|
mistachkin
|
186 |
const char *zFile = db_column_text(&q, 1); |
|
f4ceace…
|
mistachkin
|
187 |
if( bDetails ){ |
|
f4ceace…
|
mistachkin
|
188 |
const char *zTime = db_column_text(&q, 0); |
|
f4ceace…
|
mistachkin
|
189 |
int size = db_column_int(&q, 2); |
|
f4ceace…
|
mistachkin
|
190 |
char zSize[50]; |
|
f4ceace…
|
mistachkin
|
191 |
char *zSubList = 0; |
|
f4ceace…
|
mistachkin
|
192 |
int nSubList = 0; |
|
f4ceace…
|
mistachkin
|
193 |
sqlite3_snprintf(sizeof(zSize), zSize, "%d", size); |
|
f4ceace…
|
mistachkin
|
194 |
Th_ListAppend(interp, &zSubList, &nSubList, zFile, -1); |
|
f4ceace…
|
mistachkin
|
195 |
Th_ListAppend(interp, &zSubList, &nSubList, zSize, -1); |
|
f4ceace…
|
mistachkin
|
196 |
Th_ListAppend(interp, &zSubList, &nSubList, zTime, -1); |
|
f4ceace…
|
mistachkin
|
197 |
Th_ListAppend(interp, pzList, pnList, zSubList, -1); |
|
f4ceace…
|
mistachkin
|
198 |
Th_Free(interp, zSubList); |
|
f4ceace…
|
mistachkin
|
199 |
}else{ |
|
f4ceace…
|
mistachkin
|
200 |
Th_ListAppend(interp, pzList, pnList, zFile, -1); |
|
f4ceace…
|
mistachkin
|
201 |
} |
|
f4ceace…
|
mistachkin
|
202 |
} |
|
f4ceace…
|
mistachkin
|
203 |
db_finalize(&q); |
|
f4ceace…
|
mistachkin
|
204 |
} |
|
f4ceace…
|
mistachkin
|
205 |
|
|
f4ceace…
|
mistachkin
|
206 |
/* |
|
f4ceace…
|
mistachkin
|
207 |
** TH1 command: dir CHECKIN ?GLOB? ?DETAILS? |
|
f4ceace…
|
mistachkin
|
208 |
** |
|
f4ceace…
|
mistachkin
|
209 |
** Returns a list containing all files in CHECKIN. If GLOB is given only |
|
f4ceace…
|
mistachkin
|
210 |
** the files matching the pattern GLOB within CHECKIN will be returned. |
|
f4ceace…
|
mistachkin
|
211 |
** If DETAILS is non-zero, the result will be a list-of-lists, with each |
|
f4ceace…
|
mistachkin
|
212 |
** element containing at least three elements: the file name, the file |
|
f4ceace…
|
mistachkin
|
213 |
** size (in bytes), and the file last modification time (relative to the |
|
f4ceace…
|
mistachkin
|
214 |
** time zone configured for the repository). |
|
f4ceace…
|
mistachkin
|
215 |
*/ |
|
f4ceace…
|
mistachkin
|
216 |
static int dirCmd( |
|
f4ceace…
|
mistachkin
|
217 |
Th_Interp *interp, |
|
f4ceace…
|
mistachkin
|
218 |
void *ctx, |
|
f4ceace…
|
mistachkin
|
219 |
int argc, |
|
f4ceace…
|
mistachkin
|
220 |
const char **argv, |
|
f4ceace…
|
mistachkin
|
221 |
int *argl |
|
f4ceace…
|
mistachkin
|
222 |
){ |
|
f4ceace…
|
mistachkin
|
223 |
const char *zGlob = 0; |
|
f4ceace…
|
mistachkin
|
224 |
int bDetails = 0; |
|
f4ceace…
|
mistachkin
|
225 |
|
|
f4ceace…
|
mistachkin
|
226 |
if( argc<2 || argc>4 ){ |
|
f4ceace…
|
mistachkin
|
227 |
return Th_WrongNumArgs(interp, "dir CHECKIN ?GLOB? ?DETAILS?"); |
|
f4ceace…
|
mistachkin
|
228 |
} |
|
f4ceace…
|
mistachkin
|
229 |
if( argc>=3 ){ |
|
f4ceace…
|
mistachkin
|
230 |
zGlob = argv[2]; |
|
f4ceace…
|
mistachkin
|
231 |
} |
|
f4ceace…
|
mistachkin
|
232 |
if( argc>=4 && Th_ToInt(interp, argv[3], argl[3], &bDetails) ){ |
|
f4ceace…
|
mistachkin
|
233 |
return TH_ERROR; |
|
f4ceace…
|
mistachkin
|
234 |
} |
|
f4ceace…
|
mistachkin
|
235 |
if( Th_IsRepositoryOpen() ){ |
|
f4ceace…
|
mistachkin
|
236 |
char *zList = 0; |
|
f4ceace…
|
mistachkin
|
237 |
int nList = 0; |
|
f4ceace…
|
mistachkin
|
238 |
dir_cmd_rev(interp, &zList, &nList, argv[1], zGlob, bDetails); |
|
f4ceace…
|
mistachkin
|
239 |
Th_SetResult(interp, zList, nList); |
|
f4ceace…
|
mistachkin
|
240 |
Th_Free(interp, zList); |
|
f4ceace…
|
mistachkin
|
241 |
return TH_OK; |
|
f4ceace…
|
mistachkin
|
242 |
}else{ |
|
f4ceace…
|
mistachkin
|
243 |
Th_SetResult(interp, "repository unavailable", -1); |
|
f4ceace…
|
mistachkin
|
244 |
return TH_ERROR; |
|
b000db4…
|
mistachkin
|
245 |
} |
|
b000db4…
|
mistachkin
|
246 |
} |
|
b000db4…
|
mistachkin
|
247 |
|
|
b000db4…
|
mistachkin
|
248 |
/* |
|
109d8f5…
|
mistachkin
|
249 |
** TH1 command: httpize STRING |
|
fc6bb93…
|
jan.nijtmans
|
250 |
** |
|
fc6bb93…
|
jan.nijtmans
|
251 |
** Escape all characters of STRING which have special meaning in URI |
|
fc6bb93…
|
jan.nijtmans
|
252 |
** components. Return a new string result. |
|
fc6bb93…
|
jan.nijtmans
|
253 |
*/ |
|
fc6bb93…
|
jan.nijtmans
|
254 |
static int httpizeCmd( |
|
b000db4…
|
mistachkin
|
255 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
256 |
void *p, |
|
b000db4…
|
mistachkin
|
257 |
int argc, |
|
b000db4…
|
mistachkin
|
258 |
const char **argv, |
|
fc6bb93…
|
jan.nijtmans
|
259 |
int *argl |
|
fc6bb93…
|
jan.nijtmans
|
260 |
){ |
|
fc6bb93…
|
jan.nijtmans
|
261 |
char *zOut; |
|
fc6bb93…
|
jan.nijtmans
|
262 |
if( argc!=2 ){ |
|
fc6bb93…
|
jan.nijtmans
|
263 |
return Th_WrongNumArgs(interp, "httpize STRING"); |
|
fc6bb93…
|
jan.nijtmans
|
264 |
} |
|
2116238…
|
drh
|
265 |
zOut = httpize((char*)argv[1], TH1_LEN(argl[1])); |
|
fc6bb93…
|
jan.nijtmans
|
266 |
Th_SetResult(interp, zOut, -1); |
|
fc6bb93…
|
jan.nijtmans
|
267 |
free(zOut); |
|
fc6bb93…
|
jan.nijtmans
|
268 |
return TH_OK; |
|
fc6bb93…
|
jan.nijtmans
|
269 |
} |
|
fc6bb93…
|
jan.nijtmans
|
270 |
|
|
fc6bb93…
|
jan.nijtmans
|
271 |
/* |
|
588bb7c…
|
aku
|
272 |
** True if output is enabled. False if disabled. |
|
588bb7c…
|
aku
|
273 |
*/ |
|
588bb7c…
|
aku
|
274 |
static int enableOutput = 1; |
|
588bb7c…
|
aku
|
275 |
|
|
588bb7c…
|
aku
|
276 |
/* |
|
109d8f5…
|
mistachkin
|
277 |
** TH1 command: enable_output BOOLEAN |
|
588bb7c…
|
aku
|
278 |
** |
|
6908832…
|
drh
|
279 |
** Enable or disable the puts, wiki, combobox and copybtn commands. |
|
588bb7c…
|
aku
|
280 |
*/ |
|
588bb7c…
|
aku
|
281 |
static int enableOutputCmd( |
|
b000db4…
|
mistachkin
|
282 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
283 |
void *p, |
|
b000db4…
|
mistachkin
|
284 |
int argc, |
|
b000db4…
|
mistachkin
|
285 |
const char **argv, |
|
588bb7c…
|
aku
|
286 |
int *argl |
|
588bb7c…
|
aku
|
287 |
){ |
|
4f8c897…
|
drh
|
288 |
int rc; |
|
4f8c897…
|
drh
|
289 |
if( argc<2 || argc>3 ){ |
|
4f8c897…
|
drh
|
290 |
return Th_WrongNumArgs(interp, "enable_output [LABEL] BOOLEAN"); |
|
588bb7c…
|
aku
|
291 |
} |
|
4f8c897…
|
drh
|
292 |
rc = Th_ToInt(interp, argv[argc-1], argl[argc-1], &enableOutput); |
|
4f8c897…
|
drh
|
293 |
if( g.thTrace ){ |
|
2116238…
|
drh
|
294 |
Th_Trace("enable_output {%.*s} -> %d<br>\n", |
|
2116238…
|
drh
|
295 |
TH1_LEN(argl[1]),argv[1],enableOutput); |
|
4f8c897…
|
drh
|
296 |
} |
|
4f8c897…
|
drh
|
297 |
return rc; |
|
588bb7c…
|
aku
|
298 |
} |
|
588bb7c…
|
aku
|
299 |
|
|
588bb7c…
|
aku
|
300 |
/* |
|
2212ac4…
|
mistachkin
|
301 |
** Returns a name for a TH1 return code. |
|
588bb7c…
|
aku
|
302 |
*/ |
|
6c47a16…
|
mistachkin
|
303 |
const char *Th_ReturnCodeName(int rc, int nullIfOk){ |
|
b058c8a…
|
mistachkin
|
304 |
static char zRc[32]; |
|
2212ac4…
|
mistachkin
|
305 |
|
|
b058c8a…
|
mistachkin
|
306 |
switch( rc ){ |
|
6c47a16…
|
mistachkin
|
307 |
case TH_OK: return nullIfOk ? 0 : "TH_OK"; |
|
b058c8a…
|
mistachkin
|
308 |
case TH_ERROR: return "TH_ERROR"; |
|
b058c8a…
|
mistachkin
|
309 |
case TH_BREAK: return "TH_BREAK"; |
|
b058c8a…
|
mistachkin
|
310 |
case TH_RETURN: return "TH_RETURN"; |
|
b058c8a…
|
mistachkin
|
311 |
case TH_CONTINUE: return "TH_CONTINUE"; |
|
36f0e47…
|
mistachkin
|
312 |
case TH_RETURN2: return "TH_RETURN2"; |
|
b058c8a…
|
mistachkin
|
313 |
default: { |
|
2212ac4…
|
mistachkin
|
314 |
sqlite3_snprintf(sizeof(zRc), zRc, "TH1 return code %d", rc); |
|
b058c8a…
|
mistachkin
|
315 |
} |
|
b058c8a…
|
mistachkin
|
316 |
} |
|
b058c8a…
|
mistachkin
|
317 |
return zRc; |
|
b058c8a…
|
mistachkin
|
318 |
} |
|
b058c8a…
|
mistachkin
|
319 |
|
|
5173701…
|
stephan
|
320 |
/* See Th_SetOutputBlob() */ |
|
5173701…
|
stephan
|
321 |
static Blob * pThOut = 0; |
|
b058c8a…
|
mistachkin
|
322 |
/* |
|
5173701…
|
stephan
|
323 |
** Sets the th1-internal output-redirection blob and returns the |
|
5173701…
|
stephan
|
324 |
** previous value. That blob is used by certain output-generation |
|
5173701…
|
stephan
|
325 |
** routines to emit its output. It returns the previous value so that |
|
a5f00e0…
|
stephan
|
326 |
** a routine can temporarily replace the buffer with its own and |
|
5173701…
|
stephan
|
327 |
** restore it when it's done. |
|
b058c8a…
|
mistachkin
|
328 |
*/ |
|
5173701…
|
stephan
|
329 |
Blob * Th_SetOutputBlob(Blob * pOut){ |
|
5173701…
|
stephan
|
330 |
Blob * tmp = pThOut; |
|
5173701…
|
stephan
|
331 |
pThOut = pOut; |
|
5173701…
|
stephan
|
332 |
return tmp; |
|
5173701…
|
stephan
|
333 |
} |
|
5173701…
|
stephan
|
334 |
|
|
5173701…
|
stephan
|
335 |
/* |
|
5173701…
|
stephan
|
336 |
** Send text to the appropriate output: If pOut is not NULL, it is |
|
5173701…
|
stephan
|
337 |
** appended there, else to the console or to the CGI reply buffer. |
|
5173701…
|
stephan
|
338 |
** Escape all characters with special meaning to HTML if the encode |
|
9164a5d…
|
drh
|
339 |
** parameter is true. |
|
5173701…
|
stephan
|
340 |
** |
|
5173701…
|
stephan
|
341 |
** If pOut is NULL and the global pThOut is not then that blob |
|
5173701…
|
stephan
|
342 |
** is used for output. |
|
5173701…
|
stephan
|
343 |
*/ |
|
2116238…
|
drh
|
344 |
static void sendText(Blob *pOut, const char *z, int n, int encode){ |
|
5173701…
|
stephan
|
345 |
if(0==pOut && pThOut!=0){ |
|
5173701…
|
stephan
|
346 |
pOut = pThOut; |
|
5173701…
|
stephan
|
347 |
} |
|
588bb7c…
|
aku
|
348 |
if( enableOutput && n ){ |
|
2116238…
|
drh
|
349 |
if( n<0 ){ |
|
2116238…
|
drh
|
350 |
n = strlen(z); |
|
2116238…
|
drh
|
351 |
}else{ |
|
2116238…
|
drh
|
352 |
n = TH1_LEN(n); |
|
2116238…
|
drh
|
353 |
} |
|
588bb7c…
|
aku
|
354 |
if( encode ){ |
|
588bb7c…
|
aku
|
355 |
z = htmlize(z, n); |
|
588bb7c…
|
aku
|
356 |
n = strlen(z); |
|
588bb7c…
|
aku
|
357 |
} |
|
5173701…
|
stephan
|
358 |
if(pOut!=0){ |
|
5173701…
|
stephan
|
359 |
blob_append(pOut, z, n); |
|
5173701…
|
stephan
|
360 |
}else if( g.cgiOutput ){ |
|
588bb7c…
|
aku
|
361 |
cgi_append_content(z, n); |
|
588bb7c…
|
aku
|
362 |
}else{ |
|
588bb7c…
|
aku
|
363 |
fwrite(z, 1, n, stdout); |
|
d8ed5a0…
|
drh
|
364 |
fflush(stdout); |
|
588bb7c…
|
aku
|
365 |
} |
|
588bb7c…
|
aku
|
366 |
if( encode ) free((char*)z); |
|
588bb7c…
|
aku
|
367 |
} |
|
588bb7c…
|
aku
|
368 |
} |
|
588bb7c…
|
aku
|
369 |
|
|
5173701…
|
stephan
|
370 |
/* |
|
5173701…
|
stephan
|
371 |
** error-reporting counterpart of sendText(). |
|
5173701…
|
stephan
|
372 |
*/ |
|
5173701…
|
stephan
|
373 |
static void sendError(Blob * pOut, const char *z, int n, int forceCgi){ |
|
4f8c897…
|
drh
|
374 |
int savedEnable = enableOutput; |
|
4f8c897…
|
drh
|
375 |
enableOutput = 1; |
|
b058c8a…
|
mistachkin
|
376 |
if( forceCgi || g.cgiOutput ){ |
|
f5482a0…
|
wyoung
|
377 |
sendText(pOut, "<hr><p class=\"thmainError\">", -1, 0); |
|
b058c8a…
|
mistachkin
|
378 |
} |
|
5173701…
|
stephan
|
379 |
sendText(pOut,"ERROR: ", -1, 0); |
|
5173701…
|
stephan
|
380 |
sendText(pOut,(char*)z, n, 1); |
|
5173701…
|
stephan
|
381 |
sendText(pOut,forceCgi || g.cgiOutput ? "</p>" : "\n", -1, 0); |
|
4f8c897…
|
drh
|
382 |
enableOutput = savedEnable; |
|
d44207f…
|
mistachkin
|
383 |
} |
|
d44207f…
|
mistachkin
|
384 |
|
|
d44207f…
|
mistachkin
|
385 |
/* |
|
d44207f…
|
mistachkin
|
386 |
** Convert name to an rid. This function was copied from name_to_typed_rid() |
|
d44207f…
|
mistachkin
|
387 |
** in name.c; however, it has been modified to report TH1 script errors instead |
|
d44207f…
|
mistachkin
|
388 |
** of "fatal errors". |
|
d44207f…
|
mistachkin
|
389 |
*/ |
|
d44207f…
|
mistachkin
|
390 |
int th1_name_to_typed_rid( |
|
d44207f…
|
mistachkin
|
391 |
Th_Interp *interp, |
|
d44207f…
|
mistachkin
|
392 |
const char *zName, |
|
d44207f…
|
mistachkin
|
393 |
const char *zType |
|
d44207f…
|
mistachkin
|
394 |
){ |
|
d44207f…
|
mistachkin
|
395 |
int rid; |
|
d44207f…
|
mistachkin
|
396 |
|
|
d44207f…
|
mistachkin
|
397 |
if( zName==0 || zName[0]==0 ) return 0; |
|
d44207f…
|
mistachkin
|
398 |
rid = symbolic_name_to_rid(zName, zType); |
|
d44207f…
|
mistachkin
|
399 |
if( rid<0 ){ |
|
d44207f…
|
mistachkin
|
400 |
Th_SetResult(interp, "ambiguous name", -1); |
|
d44207f…
|
mistachkin
|
401 |
}else if( rid==0 ){ |
|
d44207f…
|
mistachkin
|
402 |
Th_SetResult(interp, "name not found", -1); |
|
d44207f…
|
mistachkin
|
403 |
} |
|
d44207f…
|
mistachkin
|
404 |
return rid; |
|
d44207f…
|
mistachkin
|
405 |
} |
|
d44207f…
|
mistachkin
|
406 |
|
|
d44207f…
|
mistachkin
|
407 |
/* |
|
c49030f…
|
drh
|
408 |
** Attempt to lookup the specified check-in and file name into an rid. |
|
d44207f…
|
mistachkin
|
409 |
** This function was copied from artifact_from_ci_and_filename() in |
|
d44207f…
|
mistachkin
|
410 |
** info.c; however, it has been modified to report TH1 script errors |
|
d44207f…
|
mistachkin
|
411 |
** instead of "fatal errors". |
|
d44207f…
|
mistachkin
|
412 |
*/ |
|
d44207f…
|
mistachkin
|
413 |
int th1_artifact_from_ci_and_filename( |
|
d44207f…
|
mistachkin
|
414 |
Th_Interp *interp, |
|
d44207f…
|
mistachkin
|
415 |
const char *zCI, |
|
d44207f…
|
mistachkin
|
416 |
const char *zFilename |
|
d44207f…
|
mistachkin
|
417 |
){ |
|
d44207f…
|
mistachkin
|
418 |
int cirid; |
|
d44207f…
|
mistachkin
|
419 |
Blob err; |
|
d44207f…
|
mistachkin
|
420 |
Manifest *pManifest; |
|
d44207f…
|
mistachkin
|
421 |
ManifestFile *pFile; |
|
d44207f…
|
mistachkin
|
422 |
|
|
d44207f…
|
mistachkin
|
423 |
if( zCI==0 ){ |
|
d44207f…
|
mistachkin
|
424 |
Th_SetResult(interp, "invalid check-in", -1); |
|
d44207f…
|
mistachkin
|
425 |
return 0; |
|
d44207f…
|
mistachkin
|
426 |
} |
|
d44207f…
|
mistachkin
|
427 |
if( zFilename==0 ){ |
|
d44207f…
|
mistachkin
|
428 |
Th_SetResult(interp, "invalid file name", -1); |
|
d44207f…
|
mistachkin
|
429 |
return 0; |
|
d44207f…
|
mistachkin
|
430 |
} |
|
d44207f…
|
mistachkin
|
431 |
cirid = th1_name_to_typed_rid(interp, zCI, "*"); |
|
d44207f…
|
mistachkin
|
432 |
blob_zero(&err); |
|
d44207f…
|
mistachkin
|
433 |
pManifest = manifest_get(cirid, CFTYPE_MANIFEST, &err); |
|
d44207f…
|
mistachkin
|
434 |
if( pManifest==0 ){ |
|
d44207f…
|
mistachkin
|
435 |
if( blob_size(&err)>0 ){ |
|
d44207f…
|
mistachkin
|
436 |
Th_SetResult(interp, blob_str(&err), blob_size(&err)); |
|
d44207f…
|
mistachkin
|
437 |
}else{ |
|
d44207f…
|
mistachkin
|
438 |
Th_SetResult(interp, "manifest not found", -1); |
|
d44207f…
|
mistachkin
|
439 |
} |
|
d44207f…
|
mistachkin
|
440 |
blob_reset(&err); |
|
d44207f…
|
mistachkin
|
441 |
return 0; |
|
d44207f…
|
mistachkin
|
442 |
} |
|
d44207f…
|
mistachkin
|
443 |
blob_reset(&err); |
|
d44207f…
|
mistachkin
|
444 |
manifest_file_rewind(pManifest); |
|
d44207f…
|
mistachkin
|
445 |
while( (pFile = manifest_file_next(pManifest,0))!=0 ){ |
|
d44207f…
|
mistachkin
|
446 |
if( fossil_strcmp(zFilename, pFile->zName)==0 ){ |
|
d44207f…
|
mistachkin
|
447 |
int rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", pFile->zUuid); |
|
d44207f…
|
mistachkin
|
448 |
manifest_destroy(pManifest); |
|
d44207f…
|
mistachkin
|
449 |
return rid; |
|
d44207f…
|
mistachkin
|
450 |
} |
|
d44207f…
|
mistachkin
|
451 |
} |
|
d44207f…
|
mistachkin
|
452 |
Th_SetResult(interp, "file name not found in manifest", -1); |
|
d44207f…
|
mistachkin
|
453 |
return 0; |
|
d44207f…
|
mistachkin
|
454 |
} |
|
d44207f…
|
mistachkin
|
455 |
|
|
d44207f…
|
mistachkin
|
456 |
/* |
|
8a65cd1…
|
mistachkin
|
457 |
** TH1 command: nonce |
|
8a65cd1…
|
mistachkin
|
458 |
** |
|
8a65cd1…
|
mistachkin
|
459 |
** Returns the value of the cryptographic nonce for the request being |
|
8a65cd1…
|
mistachkin
|
460 |
** processed. |
|
8a65cd1…
|
mistachkin
|
461 |
*/ |
|
8a65cd1…
|
mistachkin
|
462 |
static int nonceCmd( |
|
8a65cd1…
|
mistachkin
|
463 |
Th_Interp *interp, |
|
8a65cd1…
|
mistachkin
|
464 |
void *pConvert, |
|
8a65cd1…
|
mistachkin
|
465 |
int argc, |
|
8a65cd1…
|
mistachkin
|
466 |
const char **argv, |
|
8a65cd1…
|
mistachkin
|
467 |
int *argl |
|
8a65cd1…
|
mistachkin
|
468 |
){ |
|
8a65cd1…
|
mistachkin
|
469 |
if( argc!=1 ){ |
|
8a65cd1…
|
mistachkin
|
470 |
return Th_WrongNumArgs(interp, "nonce"); |
|
8a65cd1…
|
mistachkin
|
471 |
} |
|
8a65cd1…
|
mistachkin
|
472 |
Th_SetResult(interp, style_nonce(), -1); |
|
8a65cd1…
|
mistachkin
|
473 |
return TH_OK; |
|
8a65cd1…
|
mistachkin
|
474 |
} |
|
8a65cd1…
|
mistachkin
|
475 |
|
|
8a65cd1…
|
mistachkin
|
476 |
/* |
|
109d8f5…
|
mistachkin
|
477 |
** TH1 command: puts STRING |
|
109d8f5…
|
mistachkin
|
478 |
** TH1 command: html STRING |
|
109d8f5…
|
mistachkin
|
479 |
** |
|
35563f3…
|
drh
|
480 |
** Output STRING escaped for HTML (puts) or unchanged (html). |
|
588bb7c…
|
aku
|
481 |
*/ |
|
588bb7c…
|
aku
|
482 |
static int putsCmd( |
|
b000db4…
|
mistachkin
|
483 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
484 |
void *pConvert, |
|
b000db4…
|
mistachkin
|
485 |
int argc, |
|
b000db4…
|
mistachkin
|
486 |
const char **argv, |
|
588bb7c…
|
aku
|
487 |
int *argl |
|
588bb7c…
|
aku
|
488 |
){ |
|
2116238…
|
drh
|
489 |
int encode = *(unsigned int*)pConvert; |
|
2116238…
|
drh
|
490 |
int n; |
|
588bb7c…
|
aku
|
491 |
if( argc!=2 ){ |
|
588bb7c…
|
aku
|
492 |
return Th_WrongNumArgs(interp, "puts STRING"); |
|
588bb7c…
|
aku
|
493 |
} |
|
2116238…
|
drh
|
494 |
n = argl[1]; |
|
2116238…
|
drh
|
495 |
if( encode==0 && n>0 && TH1_TAINTED(n) ){ |
|
2116238…
|
drh
|
496 |
if( Th_ReportTaint(interp, "output string", argv[1], n) ){ |
|
2116238…
|
drh
|
497 |
return TH_ERROR; |
|
2116238…
|
drh
|
498 |
} |
|
2116238…
|
drh
|
499 |
} |
|
ded2126…
|
drh
|
500 |
sendText(0,(char*)argv[1], TH1_LEN(n), encode); |
|
71caba5…
|
mistachkin
|
501 |
return TH_OK; |
|
71caba5…
|
mistachkin
|
502 |
} |
|
71caba5…
|
mistachkin
|
503 |
|
|
71caba5…
|
mistachkin
|
504 |
/* |
|
bee6dbd…
|
mistachkin
|
505 |
** TH1 command: redirect URL ?withMethod? |
|
71caba5…
|
mistachkin
|
506 |
** |
|
bee6dbd…
|
mistachkin
|
507 |
** Issues an HTTP redirect to the specified URL and then exits the process. |
|
bee6dbd…
|
mistachkin
|
508 |
** By default, an HTTP status code of 302 is used. If the optional withMethod |
|
bee6dbd…
|
mistachkin
|
509 |
** argument is present and non-zero, an HTTP status code of 307 is used, which |
|
bee6dbd…
|
mistachkin
|
510 |
** should force the user agent to preserve the original method for the request |
|
bee6dbd…
|
mistachkin
|
511 |
** (e.g. GET, POST) instead of (possibly) forcing the user agent to change the |
|
bee6dbd…
|
mistachkin
|
512 |
** method to GET. |
|
71caba5…
|
mistachkin
|
513 |
*/ |
|
71caba5…
|
mistachkin
|
514 |
static int redirectCmd( |
|
71caba5…
|
mistachkin
|
515 |
Th_Interp *interp, |
|
71caba5…
|
mistachkin
|
516 |
void *p, |
|
71caba5…
|
mistachkin
|
517 |
int argc, |
|
71caba5…
|
mistachkin
|
518 |
const char **argv, |
|
71caba5…
|
mistachkin
|
519 |
int *argl |
|
71caba5…
|
mistachkin
|
520 |
){ |
|
bee6dbd…
|
mistachkin
|
521 |
int withMethod = 0; |
|
bee6dbd…
|
mistachkin
|
522 |
if( argc!=2 && argc!=3 ){ |
|
bee6dbd…
|
mistachkin
|
523 |
return Th_WrongNumArgs(interp, "redirect URL ?withMethod?"); |
|
71caba5…
|
mistachkin
|
524 |
} |
|
bee6dbd…
|
mistachkin
|
525 |
if( argc==3 ){ |
|
bee6dbd…
|
mistachkin
|
526 |
if( Th_ToInt(interp, argv[2], argl[2], &withMethod) ){ |
|
bee6dbd…
|
mistachkin
|
527 |
return TH_ERROR; |
|
bee6dbd…
|
mistachkin
|
528 |
} |
|
2116238…
|
drh
|
529 |
} |
|
2116238…
|
drh
|
530 |
if( TH1_TAINTED(argl[1]) |
|
2116238…
|
drh
|
531 |
&& Th_ReportTaint(interp,"redirect URL",argv[1],argl[1]) |
|
2116238…
|
drh
|
532 |
){ |
|
2116238…
|
drh
|
533 |
return TH_ERROR; |
|
bee6dbd…
|
mistachkin
|
534 |
} |
|
bee6dbd…
|
mistachkin
|
535 |
if( withMethod ){ |
|
bee6dbd…
|
mistachkin
|
536 |
cgi_redirect_with_method(argv[1]); |
|
bee6dbd…
|
mistachkin
|
537 |
}else{ |
|
bee6dbd…
|
mistachkin
|
538 |
cgi_redirect(argv[1]); |
|
bee6dbd…
|
mistachkin
|
539 |
} |
|
71caba5…
|
mistachkin
|
540 |
Th_SetResult(interp, argv[1], argl[1]); /* NOT REACHED */ |
|
f8820ef…
|
mistachkin
|
541 |
return TH_OK; |
|
f8820ef…
|
mistachkin
|
542 |
} |
|
f8820ef…
|
mistachkin
|
543 |
|
|
f8820ef…
|
mistachkin
|
544 |
/* |
|
f8820ef…
|
mistachkin
|
545 |
** TH1 command: insertCsrf |
|
f8820ef…
|
mistachkin
|
546 |
** |
|
f8820ef…
|
mistachkin
|
547 |
** While rendering a form, call this command to add the Anti-CSRF token |
|
f8820ef…
|
mistachkin
|
548 |
** as a hidden element of the form. |
|
f8820ef…
|
mistachkin
|
549 |
*/ |
|
f8820ef…
|
mistachkin
|
550 |
static int insertCsrfCmd( |
|
f8820ef…
|
mistachkin
|
551 |
Th_Interp *interp, |
|
f8820ef…
|
mistachkin
|
552 |
void *p, |
|
f8820ef…
|
mistachkin
|
553 |
int argc, |
|
f8820ef…
|
mistachkin
|
554 |
const char **argv, |
|
f8820ef…
|
mistachkin
|
555 |
int *argl |
|
f8820ef…
|
mistachkin
|
556 |
){ |
|
f8820ef…
|
mistachkin
|
557 |
if( argc!=1 ){ |
|
f8820ef…
|
mistachkin
|
558 |
return Th_WrongNumArgs(interp, "insertCsrf"); |
|
f8820ef…
|
mistachkin
|
559 |
} |
|
f8820ef…
|
mistachkin
|
560 |
login_insert_csrf_secret(); |
|
f8820ef…
|
mistachkin
|
561 |
return TH_OK; |
|
f8820ef…
|
mistachkin
|
562 |
} |
|
f8820ef…
|
mistachkin
|
563 |
|
|
f8820ef…
|
mistachkin
|
564 |
/* |
|
f8820ef…
|
mistachkin
|
565 |
** TH1 command: verifyCsrf |
|
f8820ef…
|
mistachkin
|
566 |
** |
|
f8820ef…
|
mistachkin
|
567 |
** Before using the results of a form, first call this command to verify |
|
f8820ef…
|
mistachkin
|
568 |
** that this Anti-CSRF token is present and is valid. If the Anti-CSRF token |
|
f8820ef…
|
mistachkin
|
569 |
** is missing or is incorrect, that indicates a cross-site scripting attack. |
|
f8820ef…
|
mistachkin
|
570 |
** If the event of an attack is detected, an error message is generated and |
|
f8820ef…
|
mistachkin
|
571 |
** all further processing is aborted. |
|
f8820ef…
|
mistachkin
|
572 |
*/ |
|
f8820ef…
|
mistachkin
|
573 |
static int verifyCsrfCmd( |
|
f8820ef…
|
mistachkin
|
574 |
Th_Interp *interp, |
|
f8820ef…
|
mistachkin
|
575 |
void *p, |
|
f8820ef…
|
mistachkin
|
576 |
int argc, |
|
f8820ef…
|
mistachkin
|
577 |
const char **argv, |
|
f8820ef…
|
mistachkin
|
578 |
int *argl |
|
f8820ef…
|
mistachkin
|
579 |
){ |
|
f8820ef…
|
mistachkin
|
580 |
if( argc!=1 ){ |
|
f8820ef…
|
mistachkin
|
581 |
return Th_WrongNumArgs(interp, "verifyCsrf"); |
|
f8820ef…
|
mistachkin
|
582 |
} |
|
920ace1…
|
drh
|
583 |
if( !cgi_csrf_safe(2) ){ |
|
920ace1…
|
drh
|
584 |
fossil_fatal("possible CSRF attack"); |
|
920ace1…
|
drh
|
585 |
} |
|
a470d60…
|
mistachkin
|
586 |
return TH_OK; |
|
a470d60…
|
mistachkin
|
587 |
} |
|
a470d60…
|
mistachkin
|
588 |
|
|
a470d60…
|
mistachkin
|
589 |
/* |
|
a470d60…
|
mistachkin
|
590 |
** TH1 command: verifyLogin |
|
a470d60…
|
mistachkin
|
591 |
** |
|
a470d60…
|
mistachkin
|
592 |
** Returns non-zero if the specified user name and password represent a |
|
a470d60…
|
mistachkin
|
593 |
** valid login for the repository. |
|
a470d60…
|
mistachkin
|
594 |
*/ |
|
a470d60…
|
mistachkin
|
595 |
static int verifyLoginCmd( |
|
a470d60…
|
mistachkin
|
596 |
Th_Interp *interp, |
|
a470d60…
|
mistachkin
|
597 |
void *p, |
|
a470d60…
|
mistachkin
|
598 |
int argc, |
|
a470d60…
|
mistachkin
|
599 |
const char **argv, |
|
a470d60…
|
mistachkin
|
600 |
int *argl |
|
a470d60…
|
mistachkin
|
601 |
){ |
|
a470d60…
|
mistachkin
|
602 |
const char *zUser; |
|
a470d60…
|
mistachkin
|
603 |
const char *zPass; |
|
a470d60…
|
mistachkin
|
604 |
int uid; |
|
a470d60…
|
mistachkin
|
605 |
if( argc!=3 ){ |
|
a470d60…
|
mistachkin
|
606 |
return Th_WrongNumArgs(interp, "verifyLogin userName password"); |
|
a470d60…
|
mistachkin
|
607 |
} |
|
a470d60…
|
mistachkin
|
608 |
zUser = argv[1]; |
|
a470d60…
|
mistachkin
|
609 |
zPass = argv[2]; |
|
a470d60…
|
mistachkin
|
610 |
uid = login_search_uid(&zUser, zPass); |
|
a470d60…
|
mistachkin
|
611 |
Th_SetResultInt(interp, uid!=0); |
|
a470d60…
|
mistachkin
|
612 |
if( uid==0 ) sqlite3_sleep(100); |
|
f6d29e9…
|
mistachkin
|
613 |
return TH_OK; |
|
f6d29e9…
|
mistachkin
|
614 |
} |
|
f6d29e9…
|
mistachkin
|
615 |
|
|
f6d29e9…
|
mistachkin
|
616 |
/* |
|
f6d29e9…
|
mistachkin
|
617 |
** TH1 command: markdown STRING |
|
f6d29e9…
|
mistachkin
|
618 |
** |
|
f6d29e9…
|
mistachkin
|
619 |
** Renders the input string as markdown. The result is a two-element list. |
|
f6d29e9…
|
mistachkin
|
620 |
** The first element is the text-only title string. The second element |
|
f6d29e9…
|
mistachkin
|
621 |
** contains the body, rendered as HTML. |
|
f6d29e9…
|
mistachkin
|
622 |
*/ |
|
f6d29e9…
|
mistachkin
|
623 |
static int markdownCmd( |
|
f6d29e9…
|
mistachkin
|
624 |
Th_Interp *interp, |
|
f6d29e9…
|
mistachkin
|
625 |
void *p, |
|
f6d29e9…
|
mistachkin
|
626 |
int argc, |
|
f6d29e9…
|
mistachkin
|
627 |
const char **argv, |
|
f6d29e9…
|
mistachkin
|
628 |
int *argl |
|
f6d29e9…
|
mistachkin
|
629 |
){ |
|
f6d29e9…
|
mistachkin
|
630 |
Blob src, title, body; |
|
f6d29e9…
|
mistachkin
|
631 |
char *zValue = 0; |
|
f6d29e9…
|
mistachkin
|
632 |
int nValue = 0; |
|
f6d29e9…
|
mistachkin
|
633 |
if( argc!=2 ){ |
|
f6d29e9…
|
mistachkin
|
634 |
return Th_WrongNumArgs(interp, "markdown STRING"); |
|
f6d29e9…
|
mistachkin
|
635 |
} |
|
f6d29e9…
|
mistachkin
|
636 |
blob_zero(&src); |
|
2116238…
|
drh
|
637 |
blob_init(&src, (char*)argv[1], TH1_LEN(argl[1])); |
|
f6d29e9…
|
mistachkin
|
638 |
blob_zero(&title); blob_zero(&body); |
|
f6d29e9…
|
mistachkin
|
639 |
markdown_to_html(&src, &title, &body); |
|
f6d29e9…
|
mistachkin
|
640 |
Th_ListAppend(interp, &zValue, &nValue, blob_str(&title), blob_size(&title)); |
|
f6d29e9…
|
mistachkin
|
641 |
Th_ListAppend(interp, &zValue, &nValue, blob_str(&body), blob_size(&body)); |
|
f6d29e9…
|
mistachkin
|
642 |
Th_SetResult(interp, zValue, nValue); |
|
999e33c…
|
mistachkin
|
643 |
Th_Free(interp, zValue); |
|
588bb7c…
|
aku
|
644 |
return TH_OK; |
|
588bb7c…
|
aku
|
645 |
} |
|
588bb7c…
|
aku
|
646 |
|
|
588bb7c…
|
aku
|
647 |
/* |
|
1e5548a…
|
mistachkin
|
648 |
** TH1 command: decorate STRING |
|
109d8f5…
|
mistachkin
|
649 |
** TH1 command: wiki STRING |
|
588bb7c…
|
aku
|
650 |
** |
|
1e5548a…
|
mistachkin
|
651 |
** Render the input string as wiki. For the decorate command, only links |
|
1e5548a…
|
mistachkin
|
652 |
** are handled. |
|
588bb7c…
|
aku
|
653 |
*/ |
|
588bb7c…
|
aku
|
654 |
static int wikiCmd( |
|
b000db4…
|
mistachkin
|
655 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
656 |
void *p, |
|
b000db4…
|
mistachkin
|
657 |
int argc, |
|
b000db4…
|
mistachkin
|
658 |
const char **argv, |
|
588bb7c…
|
aku
|
659 |
int *argl |
|
588bb7c…
|
aku
|
660 |
){ |
|
74e3f90…
|
drh
|
661 |
int flags = WIKI_INLINE | WIKI_NOBADLINKS | *(unsigned int*)p; |
|
588bb7c…
|
aku
|
662 |
if( argc!=2 ){ |
|
588bb7c…
|
aku
|
663 |
return Th_WrongNumArgs(interp, "wiki STRING"); |
|
588bb7c…
|
aku
|
664 |
} |
|
588bb7c…
|
aku
|
665 |
if( enableOutput ){ |
|
588bb7c…
|
aku
|
666 |
Blob src; |
|
2116238…
|
drh
|
667 |
blob_init(&src, (char*)argv[1], TH1_LEN(argl[1])); |
|
74e3f90…
|
drh
|
668 |
wiki_convert(&src, 0, flags); |
|
588bb7c…
|
aku
|
669 |
blob_reset(&src); |
|
588bb7c…
|
aku
|
670 |
} |
|
25f43cc…
|
stephan
|
671 |
return TH_OK; |
|
25f43cc…
|
stephan
|
672 |
} |
|
25f43cc…
|
stephan
|
673 |
|
|
25f43cc…
|
stephan
|
674 |
/* |
|
25f43cc…
|
stephan
|
675 |
** TH1 command: wiki_assoc STRING STRING |
|
25f43cc…
|
stephan
|
676 |
** |
|
25f43cc…
|
stephan
|
677 |
** Render an associated wiki page. The first string is the namespace |
|
25f43cc…
|
stephan
|
678 |
** (e.g. "checkin", "branch", "ticket"). The second is the ID of the |
|
25f43cc…
|
stephan
|
679 |
** associated object. See wiki_render_associated(). |
|
25f43cc…
|
stephan
|
680 |
*/ |
|
25f43cc…
|
stephan
|
681 |
static int wikiAssocCmd( |
|
25f43cc…
|
stephan
|
682 |
Th_Interp *interp, |
|
25f43cc…
|
stephan
|
683 |
void *p, |
|
25f43cc…
|
stephan
|
684 |
int argc, |
|
25f43cc…
|
stephan
|
685 |
const char **argv, |
|
25f43cc…
|
stephan
|
686 |
int *argl |
|
25f43cc…
|
stephan
|
687 |
){ |
|
25f43cc…
|
stephan
|
688 |
if( argc!=3 ){ |
|
25f43cc…
|
stephan
|
689 |
return Th_WrongNumArgs(interp, "wiki_assoc STRING STRING"); |
|
25f43cc…
|
stephan
|
690 |
} |
|
25f43cc…
|
stephan
|
691 |
wiki_render_associated((char*)argv[1], (char*)argv[2], WIKIASSOC_FULL_TITLE); |
|
109d8f5…
|
mistachkin
|
692 |
return TH_OK; |
|
109d8f5…
|
mistachkin
|
693 |
} |
|
109d8f5…
|
mistachkin
|
694 |
|
|
109d8f5…
|
mistachkin
|
695 |
/* |
|
109d8f5…
|
mistachkin
|
696 |
** TH1 command: htmlize STRING |
|
46e6a03…
|
drh
|
697 |
** |
|
46e6a03…
|
drh
|
698 |
** Escape all characters of STRING which have special meaning in HTML. |
|
46e6a03…
|
drh
|
699 |
** Return a new string result. |
|
46e6a03…
|
drh
|
700 |
*/ |
|
46e6a03…
|
drh
|
701 |
static int htmlizeCmd( |
|
b000db4…
|
mistachkin
|
702 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
703 |
void *p, |
|
b000db4…
|
mistachkin
|
704 |
int argc, |
|
b000db4…
|
mistachkin
|
705 |
const char **argv, |
|
46e6a03…
|
drh
|
706 |
int *argl |
|
46e6a03…
|
drh
|
707 |
){ |
|
46e6a03…
|
drh
|
708 |
char *zOut; |
|
46e6a03…
|
drh
|
709 |
if( argc!=2 ){ |
|
46e6a03…
|
drh
|
710 |
return Th_WrongNumArgs(interp, "htmlize STRING"); |
|
46e6a03…
|
drh
|
711 |
} |
|
2116238…
|
drh
|
712 |
zOut = htmlize((char*)argv[1], TH1_LEN(argl[1])); |
|
3f21421…
|
mistachkin
|
713 |
Th_SetResult(interp, zOut, -1); |
|
3f21421…
|
mistachkin
|
714 |
free(zOut); |
|
3f21421…
|
mistachkin
|
715 |
return TH_OK; |
|
3f21421…
|
mistachkin
|
716 |
} |
|
3f21421…
|
mistachkin
|
717 |
|
|
3f21421…
|
mistachkin
|
718 |
/* |
|
3f21421…
|
mistachkin
|
719 |
** TH1 command: encode64 STRING |
|
3f21421…
|
mistachkin
|
720 |
** |
|
3f21421…
|
mistachkin
|
721 |
** Encode the specified string using Base64 and return the result. |
|
3f21421…
|
mistachkin
|
722 |
*/ |
|
3f21421…
|
mistachkin
|
723 |
static int encode64Cmd( |
|
3f21421…
|
mistachkin
|
724 |
Th_Interp *interp, |
|
3f21421…
|
mistachkin
|
725 |
void *p, |
|
3f21421…
|
mistachkin
|
726 |
int argc, |
|
3f21421…
|
mistachkin
|
727 |
const char **argv, |
|
3f21421…
|
mistachkin
|
728 |
int *argl |
|
3f21421…
|
mistachkin
|
729 |
){ |
|
3f21421…
|
mistachkin
|
730 |
char *zOut; |
|
3f21421…
|
mistachkin
|
731 |
if( argc!=2 ){ |
|
3f21421…
|
mistachkin
|
732 |
return Th_WrongNumArgs(interp, "encode64 STRING"); |
|
3f21421…
|
mistachkin
|
733 |
} |
|
2116238…
|
drh
|
734 |
zOut = encode64((char*)argv[1], TH1_LEN(argl[1])); |
|
0c99a15…
|
drh
|
735 |
Th_SetResult(interp, zOut, -1); |
|
0c99a15…
|
drh
|
736 |
free(zOut); |
|
0c99a15…
|
drh
|
737 |
return TH_OK; |
|
0c99a15…
|
drh
|
738 |
} |
|
0c99a15…
|
drh
|
739 |
|
|
0c99a15…
|
drh
|
740 |
/* |
|
109d8f5…
|
mistachkin
|
741 |
** TH1 command: date |
|
0c99a15…
|
drh
|
742 |
** |
|
e076252…
|
drh
|
743 |
** Return a string which is the current time and date. If the |
|
e076252…
|
drh
|
744 |
** -local option is used, the date appears using localtime instead |
|
e076252…
|
drh
|
745 |
** of UTC. |
|
0c99a15…
|
drh
|
746 |
*/ |
|
0c99a15…
|
drh
|
747 |
static int dateCmd( |
|
b000db4…
|
mistachkin
|
748 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
749 |
void *p, |
|
b000db4…
|
mistachkin
|
750 |
int argc, |
|
b000db4…
|
mistachkin
|
751 |
const char **argv, |
|
0c99a15…
|
drh
|
752 |
int *argl |
|
0c99a15…
|
drh
|
753 |
){ |
|
e076252…
|
drh
|
754 |
char *zOut; |
|
2116238…
|
drh
|
755 |
if( argc>=2 && TH1_LEN(argl[1])==6 && memcmp(argv[1],"-local",6)==0 ){ |
|
ea63a2d…
|
drh
|
756 |
zOut = db_text("??", "SELECT datetime('now',toLocal())"); |
|
e076252…
|
drh
|
757 |
}else{ |
|
e076252…
|
drh
|
758 |
zOut = db_text("??", "SELECT datetime('now')"); |
|
e076252…
|
drh
|
759 |
} |
|
0c99a15…
|
drh
|
760 |
Th_SetResult(interp, zOut, -1); |
|
0c99a15…
|
drh
|
761 |
free(zOut); |
|
0c99a15…
|
drh
|
762 |
return TH_OK; |
|
0c99a15…
|
drh
|
763 |
} |
|
0c99a15…
|
drh
|
764 |
|
|
0c99a15…
|
drh
|
765 |
/* |
|
109d8f5…
|
mistachkin
|
766 |
** TH1 command: hascap STRING... |
|
653dd40…
|
drh
|
767 |
** TH1 command: anoncap STRING... |
|
0c99a15…
|
drh
|
768 |
** |
|
653dd40…
|
drh
|
769 |
** Return true if the current user (hascap) or if the anonymous user |
|
653dd40…
|
drh
|
770 |
** (anoncap) has all of the capabilities listed in STRING. |
|
0c99a15…
|
drh
|
771 |
*/ |
|
0c99a15…
|
drh
|
772 |
static int hascapCmd( |
|
b000db4…
|
mistachkin
|
773 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
774 |
void *p, |
|
b000db4…
|
mistachkin
|
775 |
int argc, |
|
b000db4…
|
mistachkin
|
776 |
const char **argv, |
|
b000db4…
|
mistachkin
|
777 |
int *argl |
|
b000db4…
|
mistachkin
|
778 |
){ |
|
1c0b1a5…
|
mistachkin
|
779 |
int rc = 1, i; |
|
901f183…
|
mistachkin
|
780 |
char *zCapList = 0; |
|
901f183…
|
mistachkin
|
781 |
int nCapList = 0; |
|
c0c0bae…
|
drh
|
782 |
if( argc<2 ){ |
|
c0c0bae…
|
drh
|
783 |
return Th_WrongNumArgs(interp, "hascap STRING ..."); |
|
c0c0bae…
|
drh
|
784 |
} |
|
1c0b1a5…
|
mistachkin
|
785 |
for(i=1; rc==1 && i<argc; i++){ |
|
901f183…
|
mistachkin
|
786 |
if( g.thTrace ){ |
|
2116238…
|
drh
|
787 |
Th_ListAppend(interp, &zCapList, &nCapList, argv[i], TH1_LEN(argl[i])); |
|
901f183…
|
mistachkin
|
788 |
} |
|
2116238…
|
drh
|
789 |
rc = login_has_capability((char*)argv[i],TH1_LEN(argl[i]),*(int*)p); |
|
c0c0bae…
|
drh
|
790 |
} |
|
c0c0bae…
|
drh
|
791 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
792 |
Th_Trace("[%s %#h] => %d<br>\n", argv[0], nCapList, zCapList, rc); |
|
901f183…
|
mistachkin
|
793 |
Th_Free(interp, zCapList); |
|
c0c0bae…
|
drh
|
794 |
} |
|
901f183…
|
mistachkin
|
795 |
Th_SetResultInt(interp, rc); |
|
901f183…
|
mistachkin
|
796 |
return TH_OK; |
|
901f183…
|
mistachkin
|
797 |
} |
|
f96de5a…
|
drh
|
798 |
|
|
f96de5a…
|
drh
|
799 |
/* |
|
f96de5a…
|
drh
|
800 |
** TH1 command: capexpr CAPABILITY-EXPR |
|
f96de5a…
|
drh
|
801 |
** |
|
f96de5a…
|
drh
|
802 |
** Nmemonic: "CAPability EXPRression" |
|
f96de5a…
|
drh
|
803 |
** |
|
f96de5a…
|
drh
|
804 |
** The capability expression is a list. Each term of the list is a cluster |
|
f96de5a…
|
drh
|
805 |
** of capability letters. The overall expression is true if any one term |
|
f96de5a…
|
drh
|
806 |
** is true. A single term is true if all letters within that term are true. |
|
f96de5a…
|
drh
|
807 |
** Or, if the term begins with "!", then the term is true if none of the |
|
f96de5a…
|
drh
|
808 |
** terms or true. Or, if the term begins with "@" then the term is true |
|
f96de5a…
|
drh
|
809 |
** if all of the capability letters in that term are available to the |
|
f96de5a…
|
drh
|
810 |
** "anonymous" user. Or, if the term is "*" then it is always true. |
|
f96de5a…
|
drh
|
811 |
** |
|
f96de5a…
|
drh
|
812 |
** Examples: |
|
f96de5a…
|
drh
|
813 |
** |
|
f96de5a…
|
drh
|
814 |
** capexpr {j o r} True if any one of j, o, or r are available |
|
f96de5a…
|
drh
|
815 |
** capexpr {oh} True if both o and h are available |
|
f96de5a…
|
drh
|
816 |
** capexpr {@2 @3 4 5 6} 2 or 3 available for anonymous or one of |
|
f96de5a…
|
drh
|
817 |
** 4, 5 or 6 is available for the user |
|
f96de5a…
|
drh
|
818 |
*/ |
|
aa5beb8…
|
drh
|
819 |
int capexprCmd( |
|
f96de5a…
|
drh
|
820 |
Th_Interp *interp, |
|
f96de5a…
|
drh
|
821 |
void *p, |
|
f96de5a…
|
drh
|
822 |
int argc, |
|
f96de5a…
|
drh
|
823 |
const char **argv, |
|
f96de5a…
|
drh
|
824 |
int *argl |
|
f96de5a…
|
drh
|
825 |
){ |
|
f96de5a…
|
drh
|
826 |
char **azCap; |
|
f96de5a…
|
drh
|
827 |
int *anCap; |
|
f96de5a…
|
drh
|
828 |
int nCap; |
|
f96de5a…
|
drh
|
829 |
int rc; |
|
f96de5a…
|
drh
|
830 |
int i; |
|
f96de5a…
|
drh
|
831 |
|
|
f96de5a…
|
drh
|
832 |
if( argc!=2 ){ |
|
f96de5a…
|
drh
|
833 |
return Th_WrongNumArgs(interp, "capexpr EXPR"); |
|
f96de5a…
|
drh
|
834 |
} |
|
2116238…
|
drh
|
835 |
rc = Th_SplitList(interp, argv[1], TH1_LEN(argl[1]), &azCap, &anCap, &nCap); |
|
f96de5a…
|
drh
|
836 |
if( rc ) return rc; |
|
f96de5a…
|
drh
|
837 |
rc = 0; |
|
f96de5a…
|
drh
|
838 |
for(i=0; i<nCap; i++){ |
|
f96de5a…
|
drh
|
839 |
if( azCap[i][0]=='!' ){ |
|
f96de5a…
|
drh
|
840 |
rc = !login_has_capability(azCap[i]+1, anCap[i]-1, 0); |
|
f96de5a…
|
drh
|
841 |
}else if( azCap[i][0]=='@' ){ |
|
f96de5a…
|
drh
|
842 |
rc = login_has_capability(azCap[i]+1, anCap[i]-1, LOGIN_ANON); |
|
f96de5a…
|
drh
|
843 |
}else if( azCap[i][0]=='*' ){ |
|
f96de5a…
|
drh
|
844 |
rc = 1; |
|
f96de5a…
|
drh
|
845 |
}else{ |
|
f96de5a…
|
drh
|
846 |
rc = login_has_capability(azCap[i], anCap[i], 0); |
|
f96de5a…
|
drh
|
847 |
} |
|
8188ef9…
|
drh
|
848 |
if( rc ) break; |
|
f96de5a…
|
drh
|
849 |
} |
|
f96de5a…
|
drh
|
850 |
Th_Free(interp, azCap); |
|
f96de5a…
|
drh
|
851 |
Th_SetResultInt(interp, rc); |
|
999e33c…
|
mistachkin
|
852 |
return TH_OK; |
|
f96de5a…
|
drh
|
853 |
} |
|
f96de5a…
|
drh
|
854 |
|
|
c0c0bae…
|
drh
|
855 |
|
|
c0c0bae…
|
drh
|
856 |
/* |
|
c0c0bae…
|
drh
|
857 |
** TH1 command: searchable STRING... |
|
c0c0bae…
|
drh
|
858 |
** |
|
c0c0bae…
|
drh
|
859 |
** Return true if searching in any of the document classes identified |
|
c0c0bae…
|
drh
|
860 |
** by STRING is enabled for the repository and user has the necessary |
|
c0c0bae…
|
drh
|
861 |
** capabilities to perform the search. |
|
c0c0bae…
|
drh
|
862 |
** |
|
c0c0bae…
|
drh
|
863 |
** Document classes: |
|
c0c0bae…
|
drh
|
864 |
** |
|
c0c0bae…
|
drh
|
865 |
** c Check-in comments |
|
c0c0bae…
|
drh
|
866 |
** d Embedded documentation |
|
c0c0bae…
|
drh
|
867 |
** t Tickets |
|
c0c0bae…
|
drh
|
868 |
** w Wiki |
|
c0c0bae…
|
drh
|
869 |
** |
|
c0c0bae…
|
drh
|
870 |
** To be clear, only one of the document classes identified by each STRING |
|
c0c0bae…
|
drh
|
871 |
** needs to be searchable in order for that argument to be true. But |
|
c0c0bae…
|
drh
|
872 |
** all arguments must be true for this routine to return true. Hence, to |
|
c0c0bae…
|
drh
|
873 |
** see if ALL document classes are searchable: |
|
b8e3dc1…
|
jan.nijtmans
|
874 |
** |
|
c0c0bae…
|
drh
|
875 |
** if {[searchable c d t w]} {...} |
|
c0c0bae…
|
drh
|
876 |
** |
|
c0c0bae…
|
drh
|
877 |
** But to see if ANY document class is searchable: |
|
c0c0bae…
|
drh
|
878 |
** |
|
c0c0bae…
|
drh
|
879 |
** if {[searchable cdtw]} {...} |
|
c0c0bae…
|
drh
|
880 |
** |
|
c0c0bae…
|
drh
|
881 |
** This command is useful for enabling or disabling a "Search" entry |
|
c0c0bae…
|
drh
|
882 |
** on the menu bar. |
|
c0c0bae…
|
drh
|
883 |
*/ |
|
c0c0bae…
|
drh
|
884 |
static int searchableCmd( |
|
c0c0bae…
|
drh
|
885 |
Th_Interp *interp, |
|
c0c0bae…
|
drh
|
886 |
void *p, |
|
c0c0bae…
|
drh
|
887 |
int argc, |
|
c0c0bae…
|
drh
|
888 |
const char **argv, |
|
c0c0bae…
|
drh
|
889 |
int *argl |
|
c0c0bae…
|
drh
|
890 |
){ |
|
c0c0bae…
|
drh
|
891 |
int rc = 1, i, j; |
|
2e9e369…
|
drh
|
892 |
unsigned int searchCap = search_restrict(SRCH_ALL); |
|
ba418ee…
|
drh
|
893 |
if( argc<2 ){ |
|
ba418ee…
|
drh
|
894 |
return Th_WrongNumArgs(interp, "hascap STRING ..."); |
|
ba418ee…
|
drh
|
895 |
} |
|
c0c0bae…
|
drh
|
896 |
for(i=1; i<argc && rc; i++){ |
|
c0c0bae…
|
drh
|
897 |
int match = 0; |
|
2116238…
|
drh
|
898 |
int nn = TH1_LEN(argl[i]); |
|
2116238…
|
drh
|
899 |
for(j=0; j<nn; j++){ |
|
c0c0bae…
|
drh
|
900 |
switch( argv[i][j] ){ |
|
c0c0bae…
|
drh
|
901 |
case 'c': match |= searchCap & SRCH_CKIN; break; |
|
c0c0bae…
|
drh
|
902 |
case 'd': match |= searchCap & SRCH_DOC; break; |
|
c0c0bae…
|
drh
|
903 |
case 't': match |= searchCap & SRCH_TKT; break; |
|
c0c0bae…
|
drh
|
904 |
case 'w': match |= searchCap & SRCH_WIKI; break; |
|
c0c0bae…
|
drh
|
905 |
} |
|
c0c0bae…
|
drh
|
906 |
} |
|
c0c0bae…
|
drh
|
907 |
if( !match ) rc = 0; |
|
a87eaae…
|
mistachkin
|
908 |
} |
|
a87eaae…
|
mistachkin
|
909 |
if( g.thTrace ){ |
|
2116238…
|
drh
|
910 |
Th_Trace("[searchable %#h] => %d<br>\n", TH1_LEN(argl[1]), argv[1], rc); |
|
a87eaae…
|
mistachkin
|
911 |
} |
|
a87eaae…
|
mistachkin
|
912 |
Th_SetResultInt(interp, rc); |
|
a87eaae…
|
mistachkin
|
913 |
return TH_OK; |
|
a87eaae…
|
mistachkin
|
914 |
} |
|
a87eaae…
|
mistachkin
|
915 |
|
|
a87eaae…
|
mistachkin
|
916 |
/* |
|
109d8f5…
|
mistachkin
|
917 |
** TH1 command: hasfeature STRING |
|
a87eaae…
|
mistachkin
|
918 |
** |
|
a87eaae…
|
mistachkin
|
919 |
** Return true if the fossil binary has the given compile-time feature |
|
a87eaae…
|
mistachkin
|
920 |
** enabled. The set of features includes: |
|
a87eaae…
|
mistachkin
|
921 |
** |
|
e10d117…
|
mistachkin
|
922 |
** "ssl" = FOSSIL_ENABLE_SSL |
|
4a880a1…
|
mistachkin
|
923 |
** "legacyMvRm" = FOSSIL_ENABLE_LEGACY_MV_RM |
|
825d78b…
|
mistachkin
|
924 |
** "execRelPaths" = FOSSIL_ENABLE_EXEC_REL_PATHS |
|
c91bafc…
|
mistachkin
|
925 |
** "th1Docs" = FOSSIL_ENABLE_TH1_DOCS |
|
1c528d3…
|
mistachkin
|
926 |
** "th1Hooks" = FOSSIL_ENABLE_TH1_HOOKS |
|
e10d117…
|
mistachkin
|
927 |
** "tcl" = FOSSIL_ENABLE_TCL |
|
6b58c67…
|
mistachkin
|
928 |
** "useTclStubs" = USE_TCL_STUBS |
|
e10d117…
|
mistachkin
|
929 |
** "tclStubs" = FOSSIL_ENABLE_TCL_STUBS |
|
e10d117…
|
mistachkin
|
930 |
** "tclPrivateStubs" = FOSSIL_ENABLE_TCL_PRIVATE_STUBS |
|
e10d117…
|
mistachkin
|
931 |
** "json" = FOSSIL_ENABLE_JSON |
|
e10d117…
|
mistachkin
|
932 |
** "markdown" = FOSSIL_ENABLE_MARKDOWN |
|
edb8237…
|
mistachkin
|
933 |
** "unicodeCmdLine" = !BROKEN_MINGW_CMDLINE |
|
7932cb3…
|
mistachkin
|
934 |
** "dynamicBuild" = FOSSIL_DYNAMIC_BUILD |
|
d5ca538…
|
mistachkin
|
935 |
** "mman" = USE_MMAN_H |
|
9129f6f…
|
mistachkin
|
936 |
** "see" = USE_SEE |
|
a87eaae…
|
mistachkin
|
937 |
** |
|
c1c8d72…
|
jan.nijtmans
|
938 |
** Specifying an unknown feature will return a value of false, it will not |
|
c1c8d72…
|
jan.nijtmans
|
939 |
** raise a script error. |
|
a87eaae…
|
mistachkin
|
940 |
*/ |
|
a87eaae…
|
mistachkin
|
941 |
static int hasfeatureCmd( |
|
b000db4…
|
mistachkin
|
942 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
943 |
void *p, |
|
b000db4…
|
mistachkin
|
944 |
int argc, |
|
b000db4…
|
mistachkin
|
945 |
const char **argv, |
|
a87eaae…
|
mistachkin
|
946 |
int *argl |
|
a87eaae…
|
mistachkin
|
947 |
){ |
|
a87eaae…
|
mistachkin
|
948 |
int rc = 0; |
|
5330d10…
|
jan.nijtmans
|
949 |
const char *zArg; |
|
a87eaae…
|
mistachkin
|
950 |
if( argc!=2 ){ |
|
a87eaae…
|
mistachkin
|
951 |
return Th_WrongNumArgs(interp, "hasfeature STRING"); |
|
a87eaae…
|
mistachkin
|
952 |
} |
|
5330d10…
|
jan.nijtmans
|
953 |
zArg = (const char *)argv[1]; |
|
a87eaae…
|
mistachkin
|
954 |
if(NULL==zArg){ |
|
a87eaae…
|
mistachkin
|
955 |
/* placeholder for following ifdefs... */ |
|
a87eaae…
|
mistachkin
|
956 |
} |
|
a87eaae…
|
mistachkin
|
957 |
#if defined(FOSSIL_ENABLE_SSL) |
|
e10d117…
|
mistachkin
|
958 |
else if( 0 == fossil_strnicmp( zArg, "ssl\0", 4 ) ){ |
|
3c941dd…
|
drh
|
959 |
rc = 1; |
|
3c941dd…
|
drh
|
960 |
} |
|
3c941dd…
|
drh
|
961 |
#endif |
|
4a880a1…
|
mistachkin
|
962 |
else if( 0 == fossil_strnicmp( zArg, "legacyMvRm\0", 11 ) ){ |
|
4a880a1…
|
mistachkin
|
963 |
rc = 1; |
|
4a880a1…
|
mistachkin
|
964 |
} |
|
825d78b…
|
mistachkin
|
965 |
#if defined(FOSSIL_ENABLE_EXEC_REL_PATHS) |
|
825d78b…
|
mistachkin
|
966 |
else if( 0 == fossil_strnicmp( zArg, "execRelPaths\0", 13 ) ){ |
|
c91bafc…
|
mistachkin
|
967 |
rc = 1; |
|
c91bafc…
|
mistachkin
|
968 |
} |
|
c91bafc…
|
mistachkin
|
969 |
#endif |
|
c91bafc…
|
mistachkin
|
970 |
#if defined(FOSSIL_ENABLE_TH1_DOCS) |
|
c91bafc…
|
mistachkin
|
971 |
else if( 0 == fossil_strnicmp( zArg, "th1Docs\0", 8 ) ){ |
|
1c528d3…
|
mistachkin
|
972 |
rc = 1; |
|
1c528d3…
|
mistachkin
|
973 |
} |
|
1c528d3…
|
mistachkin
|
974 |
#endif |
|
1c528d3…
|
mistachkin
|
975 |
#if defined(FOSSIL_ENABLE_TH1_HOOKS) |
|
1c528d3…
|
mistachkin
|
976 |
else if( 0 == fossil_strnicmp( zArg, "th1Hooks\0", 9 ) ){ |
|
6b58c67…
|
mistachkin
|
977 |
rc = 1; |
|
6b58c67…
|
mistachkin
|
978 |
} |
|
6b58c67…
|
mistachkin
|
979 |
#endif |
|
a87eaae…
|
mistachkin
|
980 |
#if defined(FOSSIL_ENABLE_TCL) |
|
e10d117…
|
mistachkin
|
981 |
else if( 0 == fossil_strnicmp( zArg, "tcl\0", 4 ) ){ |
|
6b58c67…
|
mistachkin
|
982 |
rc = 1; |
|
6b58c67…
|
mistachkin
|
983 |
} |
|
6b58c67…
|
mistachkin
|
984 |
#endif |
|
6b58c67…
|
mistachkin
|
985 |
#if defined(USE_TCL_STUBS) |
|
6b58c67…
|
mistachkin
|
986 |
else if( 0 == fossil_strnicmp( zArg, "useTclStubs\0", 12 ) ){ |
|
a87eaae…
|
mistachkin
|
987 |
rc = 1; |
|
a87eaae…
|
mistachkin
|
988 |
} |
|
a87eaae…
|
mistachkin
|
989 |
#endif |
|
a87eaae…
|
mistachkin
|
990 |
#if defined(FOSSIL_ENABLE_TCL_STUBS) |
|
e10d117…
|
mistachkin
|
991 |
else if( 0 == fossil_strnicmp( zArg, "tclStubs\0", 9 ) ){ |
|
e10d117…
|
mistachkin
|
992 |
rc = 1; |
|
e10d117…
|
mistachkin
|
993 |
} |
|
e10d117…
|
mistachkin
|
994 |
#endif |
|
e10d117…
|
mistachkin
|
995 |
#if defined(FOSSIL_ENABLE_TCL_PRIVATE_STUBS) |
|
e10d117…
|
mistachkin
|
996 |
else if( 0 == fossil_strnicmp( zArg, "tclPrivateStubs\0", 16 ) ){ |
|
a87eaae…
|
mistachkin
|
997 |
rc = 1; |
|
a87eaae…
|
mistachkin
|
998 |
} |
|
a87eaae…
|
mistachkin
|
999 |
#endif |
|
a87eaae…
|
mistachkin
|
1000 |
#if defined(FOSSIL_ENABLE_JSON) |
|
e10d117…
|
mistachkin
|
1001 |
else if( 0 == fossil_strnicmp( zArg, "json\0", 5 ) ){ |
|
e10d117…
|
mistachkin
|
1002 |
rc = 1; |
|
e10d117…
|
mistachkin
|
1003 |
} |
|
e10d117…
|
mistachkin
|
1004 |
#endif |
|
edb8237…
|
mistachkin
|
1005 |
#if !defined(BROKEN_MINGW_CMDLINE) |
|
edb8237…
|
mistachkin
|
1006 |
else if( 0 == fossil_strnicmp( zArg, "unicodeCmdLine\0", 15 ) ){ |
|
edb8237…
|
mistachkin
|
1007 |
rc = 1; |
|
edb8237…
|
mistachkin
|
1008 |
} |
|
edb8237…
|
mistachkin
|
1009 |
#endif |
|
7932cb3…
|
mistachkin
|
1010 |
#if defined(FOSSIL_DYNAMIC_BUILD) |
|
7932cb3…
|
mistachkin
|
1011 |
else if( 0 == fossil_strnicmp( zArg, "dynamicBuild\0", 13 ) ){ |
|
7932cb3…
|
mistachkin
|
1012 |
rc = 1; |
|
7932cb3…
|
mistachkin
|
1013 |
} |
|
7932cb3…
|
mistachkin
|
1014 |
#endif |
|
d5ca538…
|
mistachkin
|
1015 |
#if defined(USE_MMAN_H) |
|
d5ca538…
|
mistachkin
|
1016 |
else if( 0 == fossil_strnicmp( zArg, "mman\0", 5 ) ){ |
|
d5ca538…
|
mistachkin
|
1017 |
rc = 1; |
|
d5ca538…
|
mistachkin
|
1018 |
} |
|
d5ca538…
|
mistachkin
|
1019 |
#endif |
|
9129f6f…
|
mistachkin
|
1020 |
#if defined(USE_SEE) |
|
9129f6f…
|
mistachkin
|
1021 |
else if( 0 == fossil_strnicmp( zArg, "see\0", 4 ) ){ |
|
9129f6f…
|
mistachkin
|
1022 |
rc = 1; |
|
9129f6f…
|
mistachkin
|
1023 |
} |
|
9129f6f…
|
mistachkin
|
1024 |
#endif |
|
e10d117…
|
mistachkin
|
1025 |
else if( 0 == fossil_strnicmp( zArg, "markdown\0", 9 ) ){ |
|
a87eaae…
|
mistachkin
|
1026 |
rc = 1; |
|
ba418ee…
|
drh
|
1027 |
} |
|
2be3a87…
|
stephan
|
1028 |
if( g.thTrace ){ |
|
2116238…
|
drh
|
1029 |
Th_Trace("[hasfeature %#h] => %d<br>\n", TH1_LEN(argl[1]), zArg, rc); |
|
2be3a87…
|
stephan
|
1030 |
} |
|
2be3a87…
|
stephan
|
1031 |
Th_SetResultInt(interp, rc); |
|
2be3a87…
|
stephan
|
1032 |
return TH_OK; |
|
2be3a87…
|
stephan
|
1033 |
} |
|
2be3a87…
|
stephan
|
1034 |
|
|
a87eaae…
|
mistachkin
|
1035 |
|
|
2be3a87…
|
stephan
|
1036 |
/* |
|
109d8f5…
|
mistachkin
|
1037 |
** TH1 command: tclReady |
|
a87eaae…
|
mistachkin
|
1038 |
** |
|
a87eaae…
|
mistachkin
|
1039 |
** Return true if the fossil binary has the Tcl integration feature |
|
a87eaae…
|
mistachkin
|
1040 |
** enabled and it is currently available for use by TH1 scripts. |
|
5df13a0…
|
stephan
|
1041 |
** |
|
2be3a87…
|
stephan
|
1042 |
*/ |
|
a87eaae…
|
mistachkin
|
1043 |
static int tclReadyCmd( |
|
a87eaae…
|
mistachkin
|
1044 |
Th_Interp *interp, |
|
a87eaae…
|
mistachkin
|
1045 |
void *p, |
|
a87eaae…
|
mistachkin
|
1046 |
int argc, |
|
a87eaae…
|
mistachkin
|
1047 |
const char **argv, |
|
2be3a87…
|
stephan
|
1048 |
int *argl |
|
2be3a87…
|
stephan
|
1049 |
){ |
|
2be3a87…
|
stephan
|
1050 |
int rc = 0; |
|
a87eaae…
|
mistachkin
|
1051 |
if( argc!=1 ){ |
|
a87eaae…
|
mistachkin
|
1052 |
return Th_WrongNumArgs(interp, "tclReady"); |
|
a87eaae…
|
mistachkin
|
1053 |
} |
|
a87eaae…
|
mistachkin
|
1054 |
#if defined(FOSSIL_ENABLE_TCL) |
|
a87eaae…
|
mistachkin
|
1055 |
if( g.tcl.interp ){ |
|
a87eaae…
|
mistachkin
|
1056 |
rc = 1; |
|
a87eaae…
|
mistachkin
|
1057 |
} |
|
a87eaae…
|
mistachkin
|
1058 |
#endif |
|
a87eaae…
|
mistachkin
|
1059 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
1060 |
Th_Trace("[tclReady] => %d<br>\n", rc); |
|
9b70675…
|
drh
|
1061 |
} |
|
9b70675…
|
drh
|
1062 |
Th_SetResultInt(interp, rc); |
|
9b70675…
|
drh
|
1063 |
return TH_OK; |
|
9b70675…
|
drh
|
1064 |
} |
|
9b70675…
|
drh
|
1065 |
|
|
2be3a87…
|
stephan
|
1066 |
|
|
9b70675…
|
drh
|
1067 |
/* |
|
109d8f5…
|
mistachkin
|
1068 |
** TH1 command: anycap STRING |
|
9b70675…
|
drh
|
1069 |
** |
|
d83638e…
|
danield
|
1070 |
** Return true if the current user |
|
653dd40…
|
drh
|
1071 |
** has any one of the capabilities listed in STRING. |
|
9b70675…
|
drh
|
1072 |
*/ |
|
9b70675…
|
drh
|
1073 |
static int anycapCmd( |
|
b000db4…
|
mistachkin
|
1074 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
1075 |
void *p, |
|
b000db4…
|
mistachkin
|
1076 |
int argc, |
|
b000db4…
|
mistachkin
|
1077 |
const char **argv, |
|
9b70675…
|
drh
|
1078 |
int *argl |
|
9b70675…
|
drh
|
1079 |
){ |
|
9b70675…
|
drh
|
1080 |
int rc = 0; |
|
9b70675…
|
drh
|
1081 |
int i; |
|
2116238…
|
drh
|
1082 |
int nn; |
|
0c99a15…
|
drh
|
1083 |
if( argc!=2 ){ |
|
9b70675…
|
drh
|
1084 |
return Th_WrongNumArgs(interp, "anycap STRING"); |
|
0c99a15…
|
drh
|
1085 |
} |
|
2116238…
|
drh
|
1086 |
nn = TH1_LEN(argl[1]); |
|
2116238…
|
drh
|
1087 |
for(i=0; rc==0 && i<nn; i++){ |
|
653dd40…
|
drh
|
1088 |
rc = login_has_capability((char*)&argv[1][i],1,0); |
|
9b70675…
|
drh
|
1089 |
} |
|
f55c6a1…
|
drh
|
1090 |
if( g.thTrace ){ |
|
2116238…
|
drh
|
1091 |
Th_Trace("[anycap %#h] => %d<br>\n", TH1_LEN(argl[1]), argv[1], rc); |
|
f55c6a1…
|
drh
|
1092 |
} |
|
9b70675…
|
drh
|
1093 |
Th_SetResultInt(interp, rc); |
|
0c99a15…
|
drh
|
1094 |
return TH_OK; |
|
0c99a15…
|
drh
|
1095 |
} |
|
0c99a15…
|
drh
|
1096 |
|
|
0c99a15…
|
drh
|
1097 |
/* |
|
109d8f5…
|
mistachkin
|
1098 |
** TH1 command: combobox NAME TEXT-LIST NUMLINES |
|
588bb7c…
|
aku
|
1099 |
** |
|
588bb7c…
|
aku
|
1100 |
** Generate an HTML combobox. NAME is both the name of the |
|
588bb7c…
|
aku
|
1101 |
** CGI parameter and the name of a variable that contains the |
|
588bb7c…
|
aku
|
1102 |
** currently selected value. TEXT-LIST is a list of possible |
|
588bb7c…
|
aku
|
1103 |
** values for the combobox. NUMLINES is 1 for a true combobox. |
|
588bb7c…
|
aku
|
1104 |
** If NUMLINES is greater than one then the display is a listbox |
|
588bb7c…
|
aku
|
1105 |
** with the number of lines given. |
|
588bb7c…
|
aku
|
1106 |
*/ |
|
588bb7c…
|
aku
|
1107 |
static int comboboxCmd( |
|
588bb7c…
|
aku
|
1108 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
1109 |
void *p, |
|
b000db4…
|
mistachkin
|
1110 |
int argc, |
|
b000db4…
|
mistachkin
|
1111 |
const char **argv, |
|
588bb7c…
|
aku
|
1112 |
int *argl |
|
588bb7c…
|
aku
|
1113 |
){ |
|
588bb7c…
|
aku
|
1114 |
if( argc!=4 ){ |
|
588bb7c…
|
aku
|
1115 |
return Th_WrongNumArgs(interp, "combobox NAME TEXT-LIST NUMLINES"); |
|
588bb7c…
|
aku
|
1116 |
} |
|
588bb7c…
|
aku
|
1117 |
if( enableOutput ){ |
|
588bb7c…
|
aku
|
1118 |
int height; |
|
0c99a15…
|
drh
|
1119 |
Blob name; |
|
2116238…
|
drh
|
1120 |
int nValue = 0; |
|
588bb7c…
|
aku
|
1121 |
const char *zValue; |
|
588bb7c…
|
aku
|
1122 |
char *z, *zH; |
|
0c99a15…
|
drh
|
1123 |
int nElem; |
|
0c99a15…
|
drh
|
1124 |
int *aszElem; |
|
0c99a15…
|
drh
|
1125 |
char **azElem; |
|
0c99a15…
|
drh
|
1126 |
int i; |
|
588bb7c…
|
aku
|
1127 |
|
|
588bb7c…
|
aku
|
1128 |
if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR; |
|
2116238…
|
drh
|
1129 |
Th_SplitList(interp, argv[2], TH1_LEN(argl[2]), &azElem, &aszElem, &nElem); |
|
2116238…
|
drh
|
1130 |
blob_init(&name, (char*)argv[1], TH1_LEN(argl[1])); |
|
588bb7c…
|
aku
|
1131 |
zValue = Th_Fetch(blob_str(&name), &nValue); |
|
2116238…
|
drh
|
1132 |
nValue = TH1_LEN(nValue); |
|
73fdb8a…
|
joel
|
1133 |
zH = htmlize(blob_buffer(&name), blob_size(&name)); |
|
73fdb8a…
|
joel
|
1134 |
z = mprintf("<select id=\"%s\" name=\"%s\" size=\"%d\">", zH, zH, height); |
|
73fdb8a…
|
joel
|
1135 |
free(zH); |
|
5173701…
|
stephan
|
1136 |
sendText(0,z, -1, 0); |
|
588bb7c…
|
aku
|
1137 |
free(z); |
|
588bb7c…
|
aku
|
1138 |
blob_reset(&name); |
|
0c99a15…
|
drh
|
1139 |
for(i=0; i<nElem; i++){ |
|
0c99a15…
|
drh
|
1140 |
zH = htmlize((char*)azElem[i], aszElem[i]); |
|
b000db4…
|
mistachkin
|
1141 |
if( zValue && aszElem[i]==nValue |
|
0c99a15…
|
drh
|
1142 |
&& memcmp(zValue, azElem[i], nValue)==0 ){ |
|
3243e63…
|
drh
|
1143 |
z = mprintf("<option value=\"%s\" selected=\"selected\">%s</option>", |
|
3243e63…
|
drh
|
1144 |
zH, zH); |
|
588bb7c…
|
aku
|
1145 |
}else{ |
|
588bb7c…
|
aku
|
1146 |
z = mprintf("<option value=\"%s\">%s</option>", zH, zH); |
|
588bb7c…
|
aku
|
1147 |
} |
|
588bb7c…
|
aku
|
1148 |
free(zH); |
|
5173701…
|
stephan
|
1149 |
sendText(0,z, -1, 0); |
|
588bb7c…
|
aku
|
1150 |
free(z); |
|
588bb7c…
|
aku
|
1151 |
} |
|
5173701…
|
stephan
|
1152 |
sendText(0,"</select>", -1, 0); |
|
0c99a15…
|
drh
|
1153 |
Th_Free(interp, azElem); |
|
6908832…
|
drh
|
1154 |
} |
|
6908832…
|
drh
|
1155 |
return TH_OK; |
|
6908832…
|
drh
|
1156 |
} |
|
6908832…
|
drh
|
1157 |
|
|
6908832…
|
drh
|
1158 |
/* |
|
8ee5e55…
|
drh
|
1159 |
** TH1 command: copybtn TARGETID FLIPPED TEXT ?COPYLENGTH? |
|
6908832…
|
drh
|
1160 |
** |
|
6908832…
|
drh
|
1161 |
** Output TEXT with a click-to-copy button next to it. Loads the copybtn.js |
|
6908832…
|
drh
|
1162 |
** Javascript module, and generates HTML elements with the following IDs: |
|
6908832…
|
drh
|
1163 |
** |
|
6908832…
|
drh
|
1164 |
** TARGETID: The <span> wrapper around TEXT. |
|
6908832…
|
drh
|
1165 |
** copy-TARGETID: The <span> for the copy button. |
|
8ee5e55…
|
drh
|
1166 |
** |
|
8ee5e55…
|
drh
|
1167 |
** If the FLIPPED argument is non-zero, the copy button is displayed after TEXT. |
|
6908832…
|
drh
|
1168 |
** |
|
6908832…
|
drh
|
1169 |
** The optional COPYLENGTH argument defines the length of the substring of TEXT |
|
6908832…
|
drh
|
1170 |
** copied to clipboard: |
|
6908832…
|
drh
|
1171 |
** |
|
6908832…
|
drh
|
1172 |
** <= 0: No limit (default if the argument is omitted). |
|
6908832…
|
drh
|
1173 |
** >= 3: Truncate TEXT after COPYLENGTH (single-byte) characters. |
|
6908832…
|
drh
|
1174 |
** 1: Use the "hash-digits" setting as the limit. |
|
6908832…
|
drh
|
1175 |
** 2: Use the length appropriate for URLs as the limit (defined at |
|
6908832…
|
drh
|
1176 |
** compile-time by FOSSIL_HASH_DIGITS_URL, defaults to 16). |
|
6908832…
|
drh
|
1177 |
*/ |
|
6908832…
|
drh
|
1178 |
static int copybtnCmd( |
|
6908832…
|
drh
|
1179 |
Th_Interp *interp, |
|
6908832…
|
drh
|
1180 |
void *p, |
|
6908832…
|
drh
|
1181 |
int argc, |
|
6908832…
|
drh
|
1182 |
const char **argv, |
|
6908832…
|
drh
|
1183 |
int *argl |
|
6908832…
|
drh
|
1184 |
){ |
|
8ee5e55…
|
drh
|
1185 |
if( argc!=4 && argc!=5 ){ |
|
8ee5e55…
|
drh
|
1186 |
return Th_WrongNumArgs(interp, |
|
8ee5e55…
|
drh
|
1187 |
"copybtn TARGETID FLIPPED TEXT ?COPYLENGTH?"); |
|
6908832…
|
drh
|
1188 |
} |
|
6908832…
|
drh
|
1189 |
if( enableOutput ){ |
|
8ee5e55…
|
drh
|
1190 |
int flipped = 0; |
|
6908832…
|
drh
|
1191 |
int copylength = 0; |
|
759fbda…
|
drh
|
1192 |
char *zResult; |
|
8ee5e55…
|
drh
|
1193 |
if( Th_ToInt(interp, argv[2], argl[2], &flipped) ) return TH_ERROR; |
|
8ee5e55…
|
drh
|
1194 |
if( argc==5 ){ |
|
8ee5e55…
|
drh
|
1195 |
if( Th_ToInt(interp, argv[4], argl[4], ©length) ) return TH_ERROR; |
|
8ee5e55…
|
drh
|
1196 |
} |
|
759fbda…
|
drh
|
1197 |
zResult = style_copy_button( |
|
759fbda…
|
drh
|
1198 |
/*bOutputCGI==*/0, /*TARGETID==*/(char*)argv[1], |
|
759fbda…
|
drh
|
1199 |
flipped, copylength, "%h", /*TEXT==*/(char*)argv[3]); |
|
5173701…
|
stephan
|
1200 |
sendText(0,zResult, -1, 0); |
|
6908832…
|
drh
|
1201 |
free(zResult); |
|
109d8f5…
|
mistachkin
|
1202 |
} |
|
109d8f5…
|
mistachkin
|
1203 |
return TH_OK; |
|
109d8f5…
|
mistachkin
|
1204 |
} |
|
109d8f5…
|
mistachkin
|
1205 |
|
|
109d8f5…
|
mistachkin
|
1206 |
/* |
|
109d8f5…
|
mistachkin
|
1207 |
** TH1 command: linecount STRING MAX MIN |
|
588bb7c…
|
aku
|
1208 |
** |
|
588bb7c…
|
aku
|
1209 |
** Return one more than the number of \n characters in STRING. But |
|
588bb7c…
|
aku
|
1210 |
** never return less than MIN or more than MAX. |
|
588bb7c…
|
aku
|
1211 |
*/ |
|
588bb7c…
|
aku
|
1212 |
static int linecntCmd( |
|
588bb7c…
|
aku
|
1213 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
1214 |
void *p, |
|
b000db4…
|
mistachkin
|
1215 |
int argc, |
|
b000db4…
|
mistachkin
|
1216 |
const char **argv, |
|
588bb7c…
|
aku
|
1217 |
int *argl |
|
588bb7c…
|
aku
|
1218 |
){ |
|
0c99a15…
|
drh
|
1219 |
const char *z; |
|
588bb7c…
|
aku
|
1220 |
int size, n, i; |
|
588bb7c…
|
aku
|
1221 |
int iMin, iMax; |
|
588bb7c…
|
aku
|
1222 |
if( argc!=4 ){ |
|
588bb7c…
|
aku
|
1223 |
return Th_WrongNumArgs(interp, "linecount STRING MAX MIN"); |
|
588bb7c…
|
aku
|
1224 |
} |
|
588bb7c…
|
aku
|
1225 |
if( Th_ToInt(interp, argv[2], argl[2], &iMax) ) return TH_ERROR; |
|
588bb7c…
|
aku
|
1226 |
if( Th_ToInt(interp, argv[3], argl[3], &iMin) ) return TH_ERROR; |
|
588bb7c…
|
aku
|
1227 |
z = argv[1]; |
|
2116238…
|
drh
|
1228 |
size = TH1_LEN(argl[1]); |
|
588bb7c…
|
aku
|
1229 |
for(n=1, i=0; i<size; i++){ |
|
588bb7c…
|
aku
|
1230 |
if( z[i]=='\n' ){ |
|
588bb7c…
|
aku
|
1231 |
n++; |
|
588bb7c…
|
aku
|
1232 |
if( n>=iMax ) break; |
|
588bb7c…
|
aku
|
1233 |
} |
|
588bb7c…
|
aku
|
1234 |
} |
|
588bb7c…
|
aku
|
1235 |
if( n<iMin ) n = iMin; |
|
588bb7c…
|
aku
|
1236 |
if( n>iMax ) n = iMax; |
|
588bb7c…
|
aku
|
1237 |
Th_SetResultInt(interp, n); |
|
588bb7c…
|
aku
|
1238 |
return TH_OK; |
|
588bb7c…
|
aku
|
1239 |
} |
|
588bb7c…
|
aku
|
1240 |
|
|
588bb7c…
|
aku
|
1241 |
/* |
|
109d8f5…
|
mistachkin
|
1242 |
** TH1 command: repository ?BOOLEAN? |
|
d8ed5a0…
|
drh
|
1243 |
** |
|
d8ed5a0…
|
drh
|
1244 |
** Return the fully qualified file name of the open repository or an empty |
|
d8ed5a0…
|
drh
|
1245 |
** string if one is not currently open. Optionally, it will attempt to open |
|
d8ed5a0…
|
drh
|
1246 |
** the repository if the boolean argument is non-zero. |
|
d8ed5a0…
|
drh
|
1247 |
*/ |
|
d8ed5a0…
|
drh
|
1248 |
static int repositoryCmd( |
|
d8ed5a0…
|
drh
|
1249 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
1250 |
void *p, |
|
b000db4…
|
mistachkin
|
1251 |
int argc, |
|
b000db4…
|
mistachkin
|
1252 |
const char **argv, |
|
d8ed5a0…
|
drh
|
1253 |
int *argl |
|
d8ed5a0…
|
drh
|
1254 |
){ |
|
d8ed5a0…
|
drh
|
1255 |
if( argc!=1 && argc!=2 ){ |
|
d8ed5a0…
|
drh
|
1256 |
return Th_WrongNumArgs(interp, "repository ?BOOLEAN?"); |
|
d8ed5a0…
|
drh
|
1257 |
} |
|
d8ed5a0…
|
drh
|
1258 |
if( argc==2 ){ |
|
24273fd…
|
mistachkin
|
1259 |
int openRepository = 0; |
|
d8ed5a0…
|
drh
|
1260 |
if( Th_ToInt(interp, argv[1], argl[1], &openRepository) ){ |
|
d8ed5a0…
|
drh
|
1261 |
return TH_ERROR; |
|
d8ed5a0…
|
drh
|
1262 |
} |
|
d8ed5a0…
|
drh
|
1263 |
if( openRepository ) db_find_and_open_repository(OPEN_OK_NOT_FOUND, 0); |
|
d8ed5a0…
|
drh
|
1264 |
} |
|
d8ed5a0…
|
drh
|
1265 |
Th_SetResult(interp, g.zRepositoryName, -1); |
|
d8ed5a0…
|
drh
|
1266 |
return TH_OK; |
|
d8ed5a0…
|
drh
|
1267 |
} |
|
d8ed5a0…
|
drh
|
1268 |
|
|
57be4d5…
|
mistachkin
|
1269 |
/* |
|
109d8f5…
|
mistachkin
|
1270 |
** TH1 command: checkout ?BOOLEAN? |
|
57be4d5…
|
mistachkin
|
1271 |
** |
|
bc36fdc…
|
danield
|
1272 |
** Return the fully qualified directory name of the current check-out or an |
|
589b902…
|
mistachkin
|
1273 |
** empty string if it is not available. Optionally, it will attempt to find |
|
bc36fdc…
|
danield
|
1274 |
** the current check-out, opening the configuration ("user") database and the |
|
589b902…
|
mistachkin
|
1275 |
** repository as necessary, if the boolean argument is non-zero. |
|
57be4d5…
|
mistachkin
|
1276 |
*/ |
|
57be4d5…
|
mistachkin
|
1277 |
static int checkoutCmd( |
|
57be4d5…
|
mistachkin
|
1278 |
Th_Interp *interp, |
|
57be4d5…
|
mistachkin
|
1279 |
void *p, |
|
57be4d5…
|
mistachkin
|
1280 |
int argc, |
|
57be4d5…
|
mistachkin
|
1281 |
const char **argv, |
|
57be4d5…
|
mistachkin
|
1282 |
int *argl |
|
57be4d5…
|
mistachkin
|
1283 |
){ |
|
57be4d5…
|
mistachkin
|
1284 |
if( argc!=1 && argc!=2 ){ |
|
57be4d5…
|
mistachkin
|
1285 |
return Th_WrongNumArgs(interp, "checkout ?BOOLEAN?"); |
|
57be4d5…
|
mistachkin
|
1286 |
} |
|
57be4d5…
|
mistachkin
|
1287 |
if( argc==2 ){ |
|
589b902…
|
mistachkin
|
1288 |
int openCheckout = 0; |
|
589b902…
|
mistachkin
|
1289 |
if( Th_ToInt(interp, argv[1], argl[1], &openCheckout) ){ |
|
57be4d5…
|
mistachkin
|
1290 |
return TH_ERROR; |
|
57be4d5…
|
mistachkin
|
1291 |
} |
|
589b902…
|
mistachkin
|
1292 |
if( openCheckout ) db_open_local(0); |
|
57be4d5…
|
mistachkin
|
1293 |
} |
|
57be4d5…
|
mistachkin
|
1294 |
Th_SetResult(interp, g.zLocalRoot, -1); |
|
57be4d5…
|
mistachkin
|
1295 |
return TH_OK; |
|
57be4d5…
|
mistachkin
|
1296 |
} |
|
57be4d5…
|
mistachkin
|
1297 |
|
|
57be4d5…
|
mistachkin
|
1298 |
/* |
|
109d8f5…
|
mistachkin
|
1299 |
** TH1 command: trace STRING |
|
57be4d5…
|
mistachkin
|
1300 |
** |
|
57be4d5…
|
mistachkin
|
1301 |
** Generate a TH1 trace message if debugging is enabled. |
|
57be4d5…
|
mistachkin
|
1302 |
*/ |
|
57be4d5…
|
mistachkin
|
1303 |
static int traceCmd( |
|
57be4d5…
|
mistachkin
|
1304 |
Th_Interp *interp, |
|
57be4d5…
|
mistachkin
|
1305 |
void *p, |
|
57be4d5…
|
mistachkin
|
1306 |
int argc, |
|
57be4d5…
|
mistachkin
|
1307 |
const char **argv, |
|
57be4d5…
|
mistachkin
|
1308 |
int *argl |
|
57be4d5…
|
mistachkin
|
1309 |
){ |
|
57be4d5…
|
mistachkin
|
1310 |
if( argc!=2 ){ |
|
57be4d5…
|
mistachkin
|
1311 |
return Th_WrongNumArgs(interp, "trace STRING"); |
|
57be4d5…
|
mistachkin
|
1312 |
} |
|
57be4d5…
|
mistachkin
|
1313 |
if( g.thTrace ){ |
|
57be4d5…
|
mistachkin
|
1314 |
Th_Trace("%s", argv[1]); |
|
57be4d5…
|
mistachkin
|
1315 |
} |
|
57be4d5…
|
mistachkin
|
1316 |
Th_SetResult(interp, 0, 0); |
|
57be4d5…
|
mistachkin
|
1317 |
return TH_OK; |
|
57be4d5…
|
mistachkin
|
1318 |
} |
|
57be4d5…
|
mistachkin
|
1319 |
|
|
57be4d5…
|
mistachkin
|
1320 |
/* |
|
66ae70a…
|
drh
|
1321 |
** TH1 command: globalState NAME ?DEFAULT? |
|
66ae70a…
|
drh
|
1322 |
** |
|
66ae70a…
|
drh
|
1323 |
** Returns a string containing the value of the specified global state |
|
66ae70a…
|
drh
|
1324 |
** variable -OR- the specified default value. Currently, the supported |
|
66ae70a…
|
drh
|
1325 |
** items are: |
|
66ae70a…
|
drh
|
1326 |
** |
|
bc36fdc…
|
danield
|
1327 |
** "checkout" = The active local check-out directory, if any. |
|
66ae70a…
|
drh
|
1328 |
** "configuration" = The active configuration database file name, |
|
66ae70a…
|
drh
|
1329 |
** if any. |
|
66ae70a…
|
drh
|
1330 |
** "executable" = The fully qualified executable file name. |
|
3355835…
|
mistachkin
|
1331 |
** "flags" = The TH1 initialization flags. |
|
66ae70a…
|
drh
|
1332 |
** "log" = The error log file name, if any. |
|
66ae70a…
|
drh
|
1333 |
** "repository" = The active local repository file name, if |
|
66ae70a…
|
drh
|
1334 |
** any. |
|
66ae70a…
|
drh
|
1335 |
** "top" = The base path for the active server instance, |
|
66ae70a…
|
drh
|
1336 |
** if applicable. |
|
66ae70a…
|
drh
|
1337 |
** "user" = The active user name, if any. |
|
66ae70a…
|
drh
|
1338 |
** "vfs" = The SQLite VFS in use, if overridden. |
|
66ae70a…
|
drh
|
1339 |
** |
|
66ae70a…
|
drh
|
1340 |
** Attempts to query for unsupported global state variables will result |
|
66ae70a…
|
drh
|
1341 |
** in a script error. Additional global state variables may be exposed |
|
66ae70a…
|
drh
|
1342 |
** in the future. |
|
66ae70a…
|
drh
|
1343 |
** |
|
66ae70a…
|
drh
|
1344 |
** See also: checkout, repository, setting |
|
66ae70a…
|
drh
|
1345 |
*/ |
|
66ae70a…
|
drh
|
1346 |
static int globalStateCmd( |
|
66ae70a…
|
drh
|
1347 |
Th_Interp *interp, |
|
66ae70a…
|
drh
|
1348 |
void *p, |
|
66ae70a…
|
drh
|
1349 |
int argc, |
|
66ae70a…
|
drh
|
1350 |
const char **argv, |
|
66ae70a…
|
drh
|
1351 |
int *argl |
|
66ae70a…
|
drh
|
1352 |
){ |
|
66ae70a…
|
drh
|
1353 |
const char *zDefault = 0; |
|
66ae70a…
|
drh
|
1354 |
if( argc!=2 && argc!=3 ){ |
|
66ae70a…
|
drh
|
1355 |
return Th_WrongNumArgs(interp, "globalState NAME ?DEFAULT?"); |
|
66ae70a…
|
drh
|
1356 |
} |
|
66ae70a…
|
drh
|
1357 |
if( argc==3 ){ |
|
66ae70a…
|
drh
|
1358 |
zDefault = argv[2]; |
|
66ae70a…
|
drh
|
1359 |
} |
|
66ae70a…
|
drh
|
1360 |
if( fossil_strnicmp(argv[1], "checkout\0", 9)==0 ){ |
|
66ae70a…
|
drh
|
1361 |
Th_SetResult(interp, g.zLocalRoot ? g.zLocalRoot : zDefault, -1); |
|
66ae70a…
|
drh
|
1362 |
return TH_OK; |
|
66ae70a…
|
drh
|
1363 |
}else if( fossil_strnicmp(argv[1], "configuration\0", 14)==0 ){ |
|
66ae70a…
|
drh
|
1364 |
Th_SetResult(interp, g.zConfigDbName ? g.zConfigDbName : zDefault, -1); |
|
66ae70a…
|
drh
|
1365 |
return TH_OK; |
|
66ae70a…
|
drh
|
1366 |
}else if( fossil_strnicmp(argv[1], "executable\0", 11)==0 ){ |
|
66ae70a…
|
drh
|
1367 |
Th_SetResult(interp, g.nameOfExe ? g.nameOfExe : zDefault, -1); |
|
66ae70a…
|
drh
|
1368 |
return TH_OK; |
|
3355835…
|
mistachkin
|
1369 |
}else if( fossil_strnicmp(argv[1], "flags\0", 6)==0 ){ |
|
3355835…
|
mistachkin
|
1370 |
Th_SetResultInt(interp, g.th1Flags); |
|
3355835…
|
mistachkin
|
1371 |
return TH_OK; |
|
66ae70a…
|
drh
|
1372 |
}else if( fossil_strnicmp(argv[1], "log\0", 4)==0 ){ |
|
66ae70a…
|
drh
|
1373 |
Th_SetResult(interp, g.zErrlog ? g.zErrlog : zDefault, -1); |
|
66ae70a…
|
drh
|
1374 |
return TH_OK; |
|
66ae70a…
|
drh
|
1375 |
}else if( fossil_strnicmp(argv[1], "repository\0", 11)==0 ){ |
|
66ae70a…
|
drh
|
1376 |
Th_SetResult(interp, g.zRepositoryName ? g.zRepositoryName : zDefault, -1); |
|
66ae70a…
|
drh
|
1377 |
return TH_OK; |
|
66ae70a…
|
drh
|
1378 |
}else if( fossil_strnicmp(argv[1], "top\0", 4)==0 ){ |
|
66ae70a…
|
drh
|
1379 |
Th_SetResult(interp, g.zTop ? g.zTop : zDefault, -1); |
|
66ae70a…
|
drh
|
1380 |
return TH_OK; |
|
66ae70a…
|
drh
|
1381 |
}else if( fossil_strnicmp(argv[1], "user\0", 5)==0 ){ |
|
66ae70a…
|
drh
|
1382 |
Th_SetResult(interp, g.zLogin ? g.zLogin : zDefault, -1); |
|
66ae70a…
|
drh
|
1383 |
return TH_OK; |
|
66ae70a…
|
drh
|
1384 |
}else if( fossil_strnicmp(argv[1], "vfs\0", 4)==0 ){ |
|
66ae70a…
|
drh
|
1385 |
Th_SetResult(interp, g.zVfsName ? g.zVfsName : zDefault, -1); |
|
66ae70a…
|
drh
|
1386 |
return TH_OK; |
|
66ae70a…
|
drh
|
1387 |
}else{ |
|
2116238…
|
drh
|
1388 |
Th_ErrorMessage(interp, "unsupported global state:", |
|
2116238…
|
drh
|
1389 |
argv[1], TH1_LEN(argl[1])); |
|
66ae70a…
|
drh
|
1390 |
return TH_ERROR; |
|
66ae70a…
|
drh
|
1391 |
} |
|
66ae70a…
|
drh
|
1392 |
} |
|
66ae70a…
|
drh
|
1393 |
|
|
66ae70a…
|
drh
|
1394 |
/* |
|
109d8f5…
|
mistachkin
|
1395 |
** TH1 command: getParameter NAME ?DEFAULT? |
|
57be4d5…
|
mistachkin
|
1396 |
** |
|
57be4d5…
|
mistachkin
|
1397 |
** Return the value of the specified query parameter or the specified default |
|
57be4d5…
|
mistachkin
|
1398 |
** value when there is no matching query parameter. |
|
57be4d5…
|
mistachkin
|
1399 |
*/ |
|
57be4d5…
|
mistachkin
|
1400 |
static int getParameterCmd( |
|
57be4d5…
|
mistachkin
|
1401 |
Th_Interp *interp, |
|
57be4d5…
|
mistachkin
|
1402 |
void *p, |
|
57be4d5…
|
mistachkin
|
1403 |
int argc, |
|
57be4d5…
|
mistachkin
|
1404 |
const char **argv, |
|
57be4d5…
|
mistachkin
|
1405 |
int *argl |
|
57be4d5…
|
mistachkin
|
1406 |
){ |
|
57be4d5…
|
mistachkin
|
1407 |
const char *zDefault = 0; |
|
6a6b854…
|
drh
|
1408 |
const char *zVal; |
|
6a6b854…
|
drh
|
1409 |
int sz; |
|
57be4d5…
|
mistachkin
|
1410 |
if( argc!=2 && argc!=3 ){ |
|
57be4d5…
|
mistachkin
|
1411 |
return Th_WrongNumArgs(interp, "getParameter NAME ?DEFAULT?"); |
|
57be4d5…
|
mistachkin
|
1412 |
} |
|
57be4d5…
|
mistachkin
|
1413 |
if( argc==3 ){ |
|
57be4d5…
|
mistachkin
|
1414 |
zDefault = argv[2]; |
|
57be4d5…
|
mistachkin
|
1415 |
} |
|
6a6b854…
|
drh
|
1416 |
zVal = cgi_parameter(argv[1], zDefault); |
|
6a6b854…
|
drh
|
1417 |
sz = th_strlen(zVal); |
|
6a6b854…
|
drh
|
1418 |
Th_SetResult(interp, zVal, TH1_ADD_TAINT(sz)); |
|
57be4d5…
|
mistachkin
|
1419 |
return TH_OK; |
|
57be4d5…
|
mistachkin
|
1420 |
} |
|
57be4d5…
|
mistachkin
|
1421 |
|
|
57be4d5…
|
mistachkin
|
1422 |
/* |
|
109d8f5…
|
mistachkin
|
1423 |
** TH1 command: setParameter NAME VALUE |
|
57be4d5…
|
mistachkin
|
1424 |
** |
|
57be4d5…
|
mistachkin
|
1425 |
** Sets the value of the specified query parameter. |
|
57be4d5…
|
mistachkin
|
1426 |
*/ |
|
57be4d5…
|
mistachkin
|
1427 |
static int setParameterCmd( |
|
57be4d5…
|
mistachkin
|
1428 |
Th_Interp *interp, |
|
57be4d5…
|
mistachkin
|
1429 |
void *p, |
|
57be4d5…
|
mistachkin
|
1430 |
int argc, |
|
57be4d5…
|
mistachkin
|
1431 |
const char **argv, |
|
57be4d5…
|
mistachkin
|
1432 |
int *argl |
|
57be4d5…
|
mistachkin
|
1433 |
){ |
|
57be4d5…
|
mistachkin
|
1434 |
if( argc!=3 ){ |
|
57be4d5…
|
mistachkin
|
1435 |
return Th_WrongNumArgs(interp, "setParameter NAME VALUE"); |
|
57be4d5…
|
mistachkin
|
1436 |
} |
|
4c3e172…
|
danield
|
1437 |
cgi_replace_parameter(fossil_strdup(argv[1]), fossil_strdup(argv[2])); |
|
3355835…
|
mistachkin
|
1438 |
return TH_OK; |
|
3355835…
|
mistachkin
|
1439 |
} |
|
3355835…
|
mistachkin
|
1440 |
|
|
3355835…
|
mistachkin
|
1441 |
/* |
|
3355835…
|
mistachkin
|
1442 |
** TH1 command: reinitialize ?FLAGS? |
|
3355835…
|
mistachkin
|
1443 |
** |
|
3355835…
|
mistachkin
|
1444 |
** Reinitializes the TH1 interpreter using the specified flags. |
|
3355835…
|
mistachkin
|
1445 |
*/ |
|
3355835…
|
mistachkin
|
1446 |
static int reinitializeCmd( |
|
3355835…
|
mistachkin
|
1447 |
Th_Interp *interp, |
|
3355835…
|
mistachkin
|
1448 |
void *p, |
|
3355835…
|
mistachkin
|
1449 |
int argc, |
|
3355835…
|
mistachkin
|
1450 |
const char **argv, |
|
3355835…
|
mistachkin
|
1451 |
int *argl |
|
3355835…
|
mistachkin
|
1452 |
){ |
|
3355835…
|
mistachkin
|
1453 |
u32 flags = TH_INIT_DEFAULT; |
|
3355835…
|
mistachkin
|
1454 |
if( argc!=1 && argc!=2 ){ |
|
3355835…
|
mistachkin
|
1455 |
return Th_WrongNumArgs(interp, "reinitialize ?FLAGS?"); |
|
3355835…
|
mistachkin
|
1456 |
} |
|
3355835…
|
mistachkin
|
1457 |
if( argc==2 ){ |
|
3355835…
|
mistachkin
|
1458 |
int iFlags; |
|
3355835…
|
mistachkin
|
1459 |
if( Th_ToInt(interp, argv[1], argl[1], &iFlags) ){ |
|
3355835…
|
mistachkin
|
1460 |
return TH_ERROR; |
|
3355835…
|
mistachkin
|
1461 |
}else{ |
|
3355835…
|
mistachkin
|
1462 |
flags = (u32)iFlags; |
|
3355835…
|
mistachkin
|
1463 |
} |
|
3355835…
|
mistachkin
|
1464 |
} |
|
3355835…
|
mistachkin
|
1465 |
Th_FossilInit(flags & ~TH_INIT_FORBID_MASK); |
|
3355835…
|
mistachkin
|
1466 |
Th_SetResult(interp, 0, 0); |
|
57be4d5…
|
mistachkin
|
1467 |
return TH_OK; |
|
57be4d5…
|
mistachkin
|
1468 |
} |
|
57be4d5…
|
mistachkin
|
1469 |
|
|
57be4d5…
|
mistachkin
|
1470 |
/* |
|
109d8f5…
|
mistachkin
|
1471 |
** TH1 command: render STRING |
|
57be4d5…
|
mistachkin
|
1472 |
** |
|
57be4d5…
|
mistachkin
|
1473 |
** Renders the template and writes the results. |
|
57be4d5…
|
mistachkin
|
1474 |
*/ |
|
57be4d5…
|
mistachkin
|
1475 |
static int renderCmd( |
|
57be4d5…
|
mistachkin
|
1476 |
Th_Interp *interp, |
|
57be4d5…
|
mistachkin
|
1477 |
void *p, |
|
57be4d5…
|
mistachkin
|
1478 |
int argc, |
|
57be4d5…
|
mistachkin
|
1479 |
const char **argv, |
|
57be4d5…
|
mistachkin
|
1480 |
int *argl |
|
57be4d5…
|
mistachkin
|
1481 |
){ |
|
57be4d5…
|
mistachkin
|
1482 |
int rc; |
|
57be4d5…
|
mistachkin
|
1483 |
if( argc!=2 ){ |
|
57be4d5…
|
mistachkin
|
1484 |
return Th_WrongNumArgs(interp, "render STRING"); |
|
57be4d5…
|
mistachkin
|
1485 |
} |
|
57be4d5…
|
mistachkin
|
1486 |
rc = Th_Render(argv[1]); |
|
57be4d5…
|
mistachkin
|
1487 |
Th_SetResult(interp, 0, 0); |
|
57be4d5…
|
mistachkin
|
1488 |
return rc; |
|
57be4d5…
|
mistachkin
|
1489 |
} |
|
57be4d5…
|
mistachkin
|
1490 |
|
|
57be4d5…
|
mistachkin
|
1491 |
/* |
|
c1cb688…
|
mistachkin
|
1492 |
** TH1 command: defHeader TITLE |
|
c1cb688…
|
mistachkin
|
1493 |
** |
|
c1cb688…
|
mistachkin
|
1494 |
** Returns the default page header. |
|
c1cb688…
|
mistachkin
|
1495 |
*/ |
|
c1cb688…
|
mistachkin
|
1496 |
static int defHeaderCmd( |
|
c1cb688…
|
mistachkin
|
1497 |
Th_Interp *interp, |
|
c1cb688…
|
mistachkin
|
1498 |
void *p, |
|
c1cb688…
|
mistachkin
|
1499 |
int argc, |
|
c1cb688…
|
mistachkin
|
1500 |
const char **argv, |
|
c1cb688…
|
mistachkin
|
1501 |
int *argl |
|
c1cb688…
|
mistachkin
|
1502 |
){ |
|
c1cb688…
|
mistachkin
|
1503 |
if( argc!=1 ){ |
|
c1cb688…
|
mistachkin
|
1504 |
return Th_WrongNumArgs(interp, "defHeader"); |
|
c1cb688…
|
mistachkin
|
1505 |
} |
|
c1cb688…
|
mistachkin
|
1506 |
Th_SetResult(interp, get_default_header(), -1); |
|
c1cb688…
|
mistachkin
|
1507 |
return TH_OK; |
|
c1cb688…
|
mistachkin
|
1508 |
} |
|
c1cb688…
|
mistachkin
|
1509 |
|
|
c1cb688…
|
mistachkin
|
1510 |
/* |
|
109d8f5…
|
mistachkin
|
1511 |
** TH1 command: styleHeader TITLE |
|
57be4d5…
|
mistachkin
|
1512 |
** |
|
874a4da…
|
mistachkin
|
1513 |
** Render the configured style header for the selected skin. |
|
57be4d5…
|
mistachkin
|
1514 |
*/ |
|
57be4d5…
|
mistachkin
|
1515 |
static int styleHeaderCmd( |
|
57be4d5…
|
mistachkin
|
1516 |
Th_Interp *interp, |
|
57be4d5…
|
mistachkin
|
1517 |
void *p, |
|
57be4d5…
|
mistachkin
|
1518 |
int argc, |
|
57be4d5…
|
mistachkin
|
1519 |
const char **argv, |
|
57be4d5…
|
mistachkin
|
1520 |
int *argl |
|
57be4d5…
|
mistachkin
|
1521 |
){ |
|
57be4d5…
|
mistachkin
|
1522 |
if( argc!=2 ){ |
|
57be4d5…
|
mistachkin
|
1523 |
return Th_WrongNumArgs(interp, "styleHeader TITLE"); |
|
57be4d5…
|
mistachkin
|
1524 |
} |
|
142200b…
|
mistachkin
|
1525 |
if( Th_IsRepositoryOpen() ){ |
|
57be4d5…
|
mistachkin
|
1526 |
style_header("%s", argv[1]); |
|
57be4d5…
|
mistachkin
|
1527 |
Th_SetResult(interp, 0, 0); |
|
57be4d5…
|
mistachkin
|
1528 |
return TH_OK; |
|
57be4d5…
|
mistachkin
|
1529 |
}else{ |
|
142200b…
|
mistachkin
|
1530 |
Th_SetResult(interp, "repository unavailable", -1); |
|
57be4d5…
|
mistachkin
|
1531 |
return TH_ERROR; |
|
57be4d5…
|
mistachkin
|
1532 |
} |
|
57be4d5…
|
mistachkin
|
1533 |
} |
|
57be4d5…
|
mistachkin
|
1534 |
|
|
57be4d5…
|
mistachkin
|
1535 |
/* |
|
109d8f5…
|
mistachkin
|
1536 |
** TH1 command: styleFooter |
|
57be4d5…
|
mistachkin
|
1537 |
** |
|
874a4da…
|
mistachkin
|
1538 |
** Render the configured style footer for the selected skin. |
|
57be4d5…
|
mistachkin
|
1539 |
*/ |
|
57be4d5…
|
mistachkin
|
1540 |
static int styleFooterCmd( |
|
57be4d5…
|
mistachkin
|
1541 |
Th_Interp *interp, |
|
57be4d5…
|
mistachkin
|
1542 |
void *p, |
|
57be4d5…
|
mistachkin
|
1543 |
int argc, |
|
57be4d5…
|
mistachkin
|
1544 |
const char **argv, |
|
57be4d5…
|
mistachkin
|
1545 |
int *argl |
|
57be4d5…
|
mistachkin
|
1546 |
){ |
|
57be4d5…
|
mistachkin
|
1547 |
if( argc!=1 ){ |
|
57be4d5…
|
mistachkin
|
1548 |
return Th_WrongNumArgs(interp, "styleFooter"); |
|
57be4d5…
|
mistachkin
|
1549 |
} |
|
142200b…
|
mistachkin
|
1550 |
if( Th_IsRepositoryOpen() ){ |
|
112c713…
|
drh
|
1551 |
style_finish_page(); |
|
9c88799…
|
drh
|
1552 |
Th_SetResult(interp, 0, 0); |
|
9c88799…
|
drh
|
1553 |
return TH_OK; |
|
9c88799…
|
drh
|
1554 |
}else{ |
|
9c88799…
|
drh
|
1555 |
Th_SetResult(interp, "repository unavailable", -1); |
|
9c88799…
|
drh
|
1556 |
return TH_ERROR; |
|
9c88799…
|
drh
|
1557 |
} |
|
9c88799…
|
drh
|
1558 |
} |
|
9c88799…
|
drh
|
1559 |
|
|
9c88799…
|
drh
|
1560 |
/* |
|
fa8be1a…
|
drh
|
1561 |
** TH1 command: styleScript ?BUILTIN-FILENAME? |
|
fa8be1a…
|
drh
|
1562 |
** |
|
fa8be1a…
|
drh
|
1563 |
** Render the js.txt file from the current skin. Or, if an argument |
|
fa8be1a…
|
drh
|
1564 |
** is supplied, render the built-in filename given. |
|
9cd7428…
|
drh
|
1565 |
** |
|
9cd7428…
|
drh
|
1566 |
** By "rendering" we mean that the script is loaded and run through |
|
9cd7428…
|
drh
|
1567 |
** TH1 to expand variables and process <th1>...</th1> script. Contrast |
|
9cd7428…
|
drh
|
1568 |
** with the "builtin_request_js BUILTIN-FILENAME" command which just |
|
9cd7428…
|
drh
|
1569 |
** loads the file as-is without interpretation. |
|
9c88799…
|
drh
|
1570 |
*/ |
|
9c88799…
|
drh
|
1571 |
static int styleScriptCmd( |
|
9c88799…
|
drh
|
1572 |
Th_Interp *interp, |
|
9c88799…
|
drh
|
1573 |
void *p, |
|
9c88799…
|
drh
|
1574 |
int argc, |
|
9c88799…
|
drh
|
1575 |
const char **argv, |
|
9c88799…
|
drh
|
1576 |
int *argl |
|
9c88799…
|
drh
|
1577 |
){ |
|
fa8be1a…
|
drh
|
1578 |
if( argc!=1 && argc!=2 ){ |
|
fa8be1a…
|
drh
|
1579 |
return Th_WrongNumArgs(interp, "styleScript ?BUILTIN_NAME?"); |
|
9c88799…
|
drh
|
1580 |
} |
|
9c88799…
|
drh
|
1581 |
if( Th_IsRepositoryOpen() ){ |
|
fa8be1a…
|
drh
|
1582 |
const char *zScript; |
|
fa8be1a…
|
drh
|
1583 |
if( argc==2 ){ |
|
fa8be1a…
|
drh
|
1584 |
zScript = (const char*)builtin_file(argv[1], 0); |
|
fa8be1a…
|
drh
|
1585 |
}else{ |
|
fa8be1a…
|
drh
|
1586 |
zScript = skin_get("js"); |
|
fa8be1a…
|
drh
|
1587 |
} |
|
9c88799…
|
drh
|
1588 |
if( zScript==0 ) zScript = ""; |
|
9c88799…
|
drh
|
1589 |
Th_Render(zScript); |
|
57be4d5…
|
mistachkin
|
1590 |
Th_SetResult(interp, 0, 0); |
|
57be4d5…
|
mistachkin
|
1591 |
return TH_OK; |
|
57be4d5…
|
mistachkin
|
1592 |
}else{ |
|
142200b…
|
mistachkin
|
1593 |
Th_SetResult(interp, "repository unavailable", -1); |
|
142200b…
|
mistachkin
|
1594 |
return TH_ERROR; |
|
142200b…
|
mistachkin
|
1595 |
} |
|
71b2216…
|
george
|
1596 |
} |
|
71b2216…
|
george
|
1597 |
|
|
71b2216…
|
george
|
1598 |
/* |
|
71b2216…
|
george
|
1599 |
** TH1 command: submenu link LABEL URL |
|
71b2216…
|
george
|
1600 |
** |
|
71b2216…
|
george
|
1601 |
** Add a hyperlink to the submenu. |
|
71b2216…
|
george
|
1602 |
*/ |
|
71b2216…
|
george
|
1603 |
static int submenuCmd( |
|
71b2216…
|
george
|
1604 |
Th_Interp *interp, |
|
71b2216…
|
george
|
1605 |
void *p, |
|
71b2216…
|
george
|
1606 |
int argc, |
|
71b2216…
|
george
|
1607 |
const char **argv, |
|
71b2216…
|
george
|
1608 |
int *argl |
|
71b2216…
|
george
|
1609 |
){ |
|
71b2216…
|
george
|
1610 |
if( argc!=4 || memcmp(argv[1],"link",5)!=0 ){ |
|
71b2216…
|
george
|
1611 |
return Th_WrongNumArgs(interp, "submenu link LABEL URL"); |
|
71b2216…
|
george
|
1612 |
} |
|
71b2216…
|
george
|
1613 |
if( argl[2]==0 ){ |
|
71b2216…
|
george
|
1614 |
Th_SetResult(interp, "link's LABEL is empty", -1); |
|
71b2216…
|
george
|
1615 |
return TH_ERROR; |
|
71b2216…
|
george
|
1616 |
} |
|
71b2216…
|
george
|
1617 |
if( argl[3]==0 ){ |
|
71b2216…
|
george
|
1618 |
Th_SetResult(interp, "link's URL is empty", -1); |
|
71b2216…
|
george
|
1619 |
return TH_ERROR; |
|
71b2216…
|
george
|
1620 |
} |
|
71b2216…
|
george
|
1621 |
/* |
|
71b2216…
|
george
|
1622 |
** Label and URL are unescaped because it is expected that |
|
71b2216…
|
george
|
1623 |
** style_finish_page() provides propper escaping via %h format. |
|
71b2216…
|
george
|
1624 |
*/ |
|
71b2216…
|
george
|
1625 |
style_submenu_element( fossil_strdup(argv[2]), "%s", argv[3] ); |
|
71b2216…
|
george
|
1626 |
Th_SetResult(interp, 0, 0); |
|
71b2216…
|
george
|
1627 |
return TH_OK; |
|
9cd7428…
|
drh
|
1628 |
} |
|
9cd7428…
|
drh
|
1629 |
|
|
9cd7428…
|
drh
|
1630 |
/* |
|
9cd7428…
|
drh
|
1631 |
** TH1 command: builtin_request_js NAME |
|
9cd7428…
|
drh
|
1632 |
** |
|
9cd7428…
|
drh
|
1633 |
** Request that the built-in javascript file called NAME be added to the |
|
9cd7428…
|
drh
|
1634 |
** end of the generated page. |
|
9cd7428…
|
drh
|
1635 |
** |
|
9cd7428…
|
drh
|
1636 |
** See also: styleScript |
|
9cd7428…
|
drh
|
1637 |
*/ |
|
9cd7428…
|
drh
|
1638 |
static int builtinRequestJsCmd( |
|
9cd7428…
|
drh
|
1639 |
Th_Interp *interp, |
|
9cd7428…
|
drh
|
1640 |
void *p, |
|
9cd7428…
|
drh
|
1641 |
int argc, |
|
9cd7428…
|
drh
|
1642 |
const char **argv, |
|
9cd7428…
|
drh
|
1643 |
int *argl |
|
9cd7428…
|
drh
|
1644 |
){ |
|
9cd7428…
|
drh
|
1645 |
if( argc!=2 ){ |
|
9cd7428…
|
drh
|
1646 |
return Th_WrongNumArgs(interp, "builtin_request_js NAME"); |
|
9cd7428…
|
drh
|
1647 |
} |
|
9cd7428…
|
drh
|
1648 |
builtin_request_js(argv[1]); |
|
9cd7428…
|
drh
|
1649 |
return TH_OK; |
|
9cd7428…
|
drh
|
1650 |
} |
|
00e4fed…
|
mistachkin
|
1651 |
|
|
00e4fed…
|
mistachkin
|
1652 |
/* |
|
00e4fed…
|
mistachkin
|
1653 |
** TH1 command: artifact ID ?FILENAME? |
|
109d8f5…
|
mistachkin
|
1654 |
** |
|
109d8f5…
|
mistachkin
|
1655 |
** Attempts to locate the specified artifact and return its contents. An |
|
109d8f5…
|
mistachkin
|
1656 |
** error is generated if the repository is not open or the artifact cannot |
|
109d8f5…
|
mistachkin
|
1657 |
** be found. |
|
109d8f5…
|
mistachkin
|
1658 |
*/ |
|
109d8f5…
|
mistachkin
|
1659 |
static int artifactCmd( |
|
109d8f5…
|
mistachkin
|
1660 |
Th_Interp *interp, |
|
109d8f5…
|
mistachkin
|
1661 |
void *p, |
|
109d8f5…
|
mistachkin
|
1662 |
int argc, |
|
109d8f5…
|
mistachkin
|
1663 |
const char **argv, |
|
109d8f5…
|
mistachkin
|
1664 |
int *argl |
|
109d8f5…
|
mistachkin
|
1665 |
){ |
|
00e4fed…
|
mistachkin
|
1666 |
if( argc!=2 && argc!=3 ){ |
|
00e4fed…
|
mistachkin
|
1667 |
return Th_WrongNumArgs(interp, "artifact ID ?FILENAME?"); |
|
109d8f5…
|
mistachkin
|
1668 |
} |
|
109d8f5…
|
mistachkin
|
1669 |
if( Th_IsRepositoryOpen() ){ |
|
109d8f5…
|
mistachkin
|
1670 |
int rid; |
|
109d8f5…
|
mistachkin
|
1671 |
Blob content; |
|
00e4fed…
|
mistachkin
|
1672 |
if( argc==3 ){ |
|
d44207f…
|
mistachkin
|
1673 |
rid = th1_artifact_from_ci_and_filename(interp, argv[1], argv[2]); |
|
00e4fed…
|
mistachkin
|
1674 |
}else{ |
|
d44207f…
|
mistachkin
|
1675 |
rid = th1_name_to_typed_rid(interp, argv[1], "*"); |
|
00e4fed…
|
mistachkin
|
1676 |
} |
|
109d8f5…
|
mistachkin
|
1677 |
if( rid!=0 && content_get(rid, &content) ){ |
|
109d8f5…
|
mistachkin
|
1678 |
Th_SetResult(interp, blob_str(&content), blob_size(&content)); |
|
74099a5…
|
mistachkin
|
1679 |
blob_reset(&content); |
|
74099a5…
|
mistachkin
|
1680 |
return TH_OK; |
|
74099a5…
|
mistachkin
|
1681 |
}else{ |
|
d44207f…
|
mistachkin
|
1682 |
return TH_ERROR; |
|
d44207f…
|
mistachkin
|
1683 |
} |
|
d44207f…
|
mistachkin
|
1684 |
}else{ |
|
d44207f…
|
mistachkin
|
1685 |
Th_SetResult(interp, "repository unavailable", -1); |
|
d44207f…
|
mistachkin
|
1686 |
return TH_ERROR; |
|
d44207f…
|
mistachkin
|
1687 |
} |
|
d44207f…
|
mistachkin
|
1688 |
} |
|
d44207f…
|
mistachkin
|
1689 |
|
|
1b5b69f…
|
mistachkin
|
1690 |
/* |
|
32c4880…
|
mistachkin
|
1691 |
** TH1 command: cgiHeaderLine line |
|
32c4880…
|
mistachkin
|
1692 |
** |
|
32c4880…
|
mistachkin
|
1693 |
** Adds the specified line to the CGI header. |
|
32c4880…
|
mistachkin
|
1694 |
*/ |
|
32c4880…
|
mistachkin
|
1695 |
static int cgiHeaderLineCmd( |
|
32c4880…
|
mistachkin
|
1696 |
Th_Interp *interp, |
|
32c4880…
|
mistachkin
|
1697 |
void *p, |
|
32c4880…
|
mistachkin
|
1698 |
int argc, |
|
32c4880…
|
mistachkin
|
1699 |
const char **argv, |
|
32c4880…
|
mistachkin
|
1700 |
int *argl |
|
32c4880…
|
mistachkin
|
1701 |
){ |
|
32c4880…
|
mistachkin
|
1702 |
if( argc!=2 ){ |
|
32c4880…
|
mistachkin
|
1703 |
return Th_WrongNumArgs(interp, "cgiHeaderLine line"); |
|
32c4880…
|
mistachkin
|
1704 |
} |
|
32c4880…
|
mistachkin
|
1705 |
cgi_append_header(argv[1]); |
|
32c4880…
|
mistachkin
|
1706 |
return TH_OK; |
|
32c4880…
|
mistachkin
|
1707 |
} |
|
32c4880…
|
mistachkin
|
1708 |
|
|
32c4880…
|
mistachkin
|
1709 |
/* |
|
1b5b69f…
|
mistachkin
|
1710 |
** TH1 command: unversioned content FILENAME |
|
1b5b69f…
|
mistachkin
|
1711 |
** |
|
1b5b69f…
|
mistachkin
|
1712 |
** Attempts to locate the specified unversioned file and return its contents. |
|
1b5b69f…
|
mistachkin
|
1713 |
** An error is generated if the repository is not open or the unversioned file |
|
1b5b69f…
|
mistachkin
|
1714 |
** cannot be found. |
|
1b5b69f…
|
mistachkin
|
1715 |
*/ |
|
1b5b69f…
|
mistachkin
|
1716 |
static int unversionedContentCmd( |
|
1b5b69f…
|
mistachkin
|
1717 |
Th_Interp *interp, |
|
1b5b69f…
|
mistachkin
|
1718 |
void *p, |
|
1b5b69f…
|
mistachkin
|
1719 |
int argc, |
|
1b5b69f…
|
mistachkin
|
1720 |
const char **argv, |
|
1b5b69f…
|
mistachkin
|
1721 |
int *argl |
|
1b5b69f…
|
mistachkin
|
1722 |
){ |
|
1b5b69f…
|
mistachkin
|
1723 |
if( argc!=3 ){ |
|
1b5b69f…
|
mistachkin
|
1724 |
return Th_WrongNumArgs(interp, "unversioned content FILENAME"); |
|
1b5b69f…
|
mistachkin
|
1725 |
} |
|
1b5b69f…
|
mistachkin
|
1726 |
if( Th_IsRepositoryOpen() ){ |
|
1b5b69f…
|
mistachkin
|
1727 |
Blob content; |
|
b5ab1eb…
|
drh
|
1728 |
if( unversioned_content(argv[2], &content)!=0 ){ |
|
1b5b69f…
|
mistachkin
|
1729 |
Th_SetResult(interp, blob_str(&content), blob_size(&content)); |
|
1b5b69f…
|
mistachkin
|
1730 |
blob_reset(&content); |
|
1b5b69f…
|
mistachkin
|
1731 |
return TH_OK; |
|
1b5b69f…
|
mistachkin
|
1732 |
}else{ |
|
1b5b69f…
|
mistachkin
|
1733 |
return TH_ERROR; |
|
1b5b69f…
|
mistachkin
|
1734 |
} |
|
1b5b69f…
|
mistachkin
|
1735 |
}else{ |
|
1b5b69f…
|
mistachkin
|
1736 |
Th_SetResult(interp, "repository unavailable", -1); |
|
1b5b69f…
|
mistachkin
|
1737 |
return TH_ERROR; |
|
1b5b69f…
|
mistachkin
|
1738 |
} |
|
1b5b69f…
|
mistachkin
|
1739 |
} |
|
d44207f…
|
mistachkin
|
1740 |
|
|
d44207f…
|
mistachkin
|
1741 |
/* |
|
1b5b69f…
|
mistachkin
|
1742 |
** TH1 command: unversioned list |
|
1b5b69f…
|
mistachkin
|
1743 |
** |
|
1b5b69f…
|
mistachkin
|
1744 |
** Returns a list of the names of all unversioned files held in the local |
|
1b5b69f…
|
mistachkin
|
1745 |
** repository. An error is generated if the repository is not open. |
|
d44207f…
|
mistachkin
|
1746 |
*/ |
|
1b5b69f…
|
mistachkin
|
1747 |
static int unversionedListCmd( |
|
1b5b69f…
|
mistachkin
|
1748 |
Th_Interp *interp, |
|
1b5b69f…
|
mistachkin
|
1749 |
void *p, |
|
1b5b69f…
|
mistachkin
|
1750 |
int argc, |
|
1b5b69f…
|
mistachkin
|
1751 |
const char **argv, |
|
1b5b69f…
|
mistachkin
|
1752 |
int *argl |
|
1b5b69f…
|
mistachkin
|
1753 |
){ |
|
1b5b69f…
|
mistachkin
|
1754 |
if( argc!=2 ){ |
|
1b5b69f…
|
mistachkin
|
1755 |
return Th_WrongNumArgs(interp, "unversioned list"); |
|
1b5b69f…
|
mistachkin
|
1756 |
} |
|
1b5b69f…
|
mistachkin
|
1757 |
if( Th_IsRepositoryOpen() ){ |
|
1b5b69f…
|
mistachkin
|
1758 |
Stmt q; |
|
1b5b69f…
|
mistachkin
|
1759 |
char *zList = 0; |
|
1b5b69f…
|
mistachkin
|
1760 |
int nList = 0; |
|
1b5b69f…
|
mistachkin
|
1761 |
db_prepare(&q, "SELECT name FROM unversioned WHERE hash IS NOT NULL" |
|
1b5b69f…
|
mistachkin
|
1762 |
" ORDER BY name"); |
|
1b5b69f…
|
mistachkin
|
1763 |
while( db_step(&q)==SQLITE_ROW ){ |
|
1b5b69f…
|
mistachkin
|
1764 |
Th_ListAppend(interp, &zList, &nList, db_column_text(&q,0), -1); |
|
1b5b69f…
|
mistachkin
|
1765 |
} |
|
1b5b69f…
|
mistachkin
|
1766 |
db_finalize(&q); |
|
1b5b69f…
|
mistachkin
|
1767 |
Th_SetResult(interp, zList, nList); |
|
1b5b69f…
|
mistachkin
|
1768 |
Th_Free(interp, zList); |
|
1b5b69f…
|
mistachkin
|
1769 |
return TH_OK; |
|
1b5b69f…
|
mistachkin
|
1770 |
}else{ |
|
1b5b69f…
|
mistachkin
|
1771 |
Th_SetResult(interp, "repository unavailable", -1); |
|
1b5b69f…
|
mistachkin
|
1772 |
return TH_ERROR; |
|
1b5b69f…
|
mistachkin
|
1773 |
} |
|
1b5b69f…
|
mistachkin
|
1774 |
} |
|
1b5b69f…
|
mistachkin
|
1775 |
|
|
1b5b69f…
|
mistachkin
|
1776 |
static int unversionedCmd( |
|
1b5b69f…
|
mistachkin
|
1777 |
Th_Interp *interp, |
|
1b5b69f…
|
mistachkin
|
1778 |
void *p, |
|
1b5b69f…
|
mistachkin
|
1779 |
int argc, |
|
1b5b69f…
|
mistachkin
|
1780 |
const char **argv, |
|
1b5b69f…
|
mistachkin
|
1781 |
int *argl |
|
1b5b69f…
|
mistachkin
|
1782 |
){ |
|
1b5b69f…
|
mistachkin
|
1783 |
static const Th_SubCommand aSub[] = { |
|
1b5b69f…
|
mistachkin
|
1784 |
{ "content", unversionedContentCmd }, |
|
1b5b69f…
|
mistachkin
|
1785 |
{ "list", unversionedListCmd }, |
|
1b5b69f…
|
mistachkin
|
1786 |
{ 0, 0 } |
|
1b5b69f…
|
mistachkin
|
1787 |
}; |
|
1b5b69f…
|
mistachkin
|
1788 |
return Th_CallSubCommand(interp, p, argc, argv, argl, aSub); |
|
1b5b69f…
|
mistachkin
|
1789 |
} |
|
1b5b69f…
|
mistachkin
|
1790 |
|
|
109d8f5…
|
mistachkin
|
1791 |
|
|
109d8f5…
|
mistachkin
|
1792 |
/* |
|
109d8f5…
|
mistachkin
|
1793 |
** TH1 command: utime |
|
3d50bdc…
|
drh
|
1794 |
** |
|
3d50bdc…
|
drh
|
1795 |
** Return the number of microseconds of CPU time consumed by the current |
|
3d50bdc…
|
drh
|
1796 |
** process in user space. |
|
3d50bdc…
|
drh
|
1797 |
*/ |
|
3d50bdc…
|
drh
|
1798 |
static int utimeCmd( |
|
3d50bdc…
|
drh
|
1799 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
1800 |
void *p, |
|
b000db4…
|
mistachkin
|
1801 |
int argc, |
|
b000db4…
|
mistachkin
|
1802 |
const char **argv, |
|
db0c512…
|
drh
|
1803 |
int *argl |
|
db0c512…
|
drh
|
1804 |
){ |
|
db0c512…
|
drh
|
1805 |
sqlite3_uint64 x; |
|
db0c512…
|
drh
|
1806 |
char zUTime[50]; |
|
6c3d370…
|
drh
|
1807 |
fossil_cpu_times(&x, 0); |
|
db0c512…
|
drh
|
1808 |
sqlite3_snprintf(sizeof(zUTime), zUTime, "%llu", x); |
|
db0c512…
|
drh
|
1809 |
Th_SetResult(interp, zUTime, -1); |
|
db0c512…
|
drh
|
1810 |
return TH_OK; |
|
db0c512…
|
drh
|
1811 |
} |
|
db0c512…
|
drh
|
1812 |
|
|
db0c512…
|
drh
|
1813 |
/* |
|
109d8f5…
|
mistachkin
|
1814 |
** TH1 command: stime |
|
db0c512…
|
drh
|
1815 |
** |
|
db0c512…
|
drh
|
1816 |
** Return the number of microseconds of CPU time consumed by the current |
|
db0c512…
|
drh
|
1817 |
** process in system space. |
|
db0c512…
|
drh
|
1818 |
*/ |
|
db0c512…
|
drh
|
1819 |
static int stimeCmd( |
|
db0c512…
|
drh
|
1820 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
1821 |
void *p, |
|
b000db4…
|
mistachkin
|
1822 |
int argc, |
|
b000db4…
|
mistachkin
|
1823 |
const char **argv, |
|
3d50bdc…
|
drh
|
1824 |
int *argl |
|
3d50bdc…
|
drh
|
1825 |
){ |
|
3d50bdc…
|
drh
|
1826 |
sqlite3_uint64 x; |
|
3d50bdc…
|
drh
|
1827 |
char zUTime[50]; |
|
6c3d370…
|
drh
|
1828 |
fossil_cpu_times(0, &x); |
|
3d50bdc…
|
drh
|
1829 |
sqlite3_snprintf(sizeof(zUTime), zUTime, "%llu", x); |
|
3d50bdc…
|
drh
|
1830 |
Th_SetResult(interp, zUTime, -1); |
|
3d50bdc…
|
drh
|
1831 |
return TH_OK; |
|
3d50bdc…
|
drh
|
1832 |
} |
|
3d50bdc…
|
drh
|
1833 |
|
|
2116238…
|
drh
|
1834 |
/* |
|
2116238…
|
drh
|
1835 |
** TH1 command: taint STRING |
|
2116238…
|
drh
|
1836 |
** |
|
2116238…
|
drh
|
1837 |
** Return a copy of STRING that is marked as tainted. |
|
2116238…
|
drh
|
1838 |
*/ |
|
2116238…
|
drh
|
1839 |
static int taintCmd( |
|
2116238…
|
drh
|
1840 |
Th_Interp *interp, |
|
2116238…
|
drh
|
1841 |
void *p, |
|
2116238…
|
drh
|
1842 |
int argc, |
|
2116238…
|
drh
|
1843 |
const char **argv, |
|
2116238…
|
drh
|
1844 |
int *argl |
|
2116238…
|
drh
|
1845 |
){ |
|
2116238…
|
drh
|
1846 |
if( argc!=2 ){ |
|
2116238…
|
drh
|
1847 |
return Th_WrongNumArgs(interp, "STRING"); |
|
2116238…
|
drh
|
1848 |
} |
|
2116238…
|
drh
|
1849 |
Th_SetResult(interp, argv[1], TH1_ADD_TAINT(argl[1])); |
|
2116238…
|
drh
|
1850 |
return TH_OK; |
|
2116238…
|
drh
|
1851 |
} |
|
2116238…
|
drh
|
1852 |
|
|
2116238…
|
drh
|
1853 |
/* |
|
2116238…
|
drh
|
1854 |
** TH1 command: untaint STRING |
|
2116238…
|
drh
|
1855 |
** |
|
2116238…
|
drh
|
1856 |
** Return a copy of STRING that is marked as untainted. |
|
2116238…
|
drh
|
1857 |
*/ |
|
2116238…
|
drh
|
1858 |
static int untaintCmd( |
|
2116238…
|
drh
|
1859 |
Th_Interp *interp, |
|
2116238…
|
drh
|
1860 |
void *p, |
|
2116238…
|
drh
|
1861 |
int argc, |
|
2116238…
|
drh
|
1862 |
const char **argv, |
|
2116238…
|
drh
|
1863 |
int *argl |
|
2116238…
|
drh
|
1864 |
){ |
|
2116238…
|
drh
|
1865 |
if( argc!=2 ){ |
|
2116238…
|
drh
|
1866 |
return Th_WrongNumArgs(interp, "STRING"); |
|
2116238…
|
drh
|
1867 |
} |
|
2116238…
|
drh
|
1868 |
Th_SetResult(interp, argv[1], TH1_LEN(argl[1])); |
|
2116238…
|
drh
|
1869 |
return TH_OK; |
|
2116238…
|
drh
|
1870 |
} |
|
74e3f90…
|
drh
|
1871 |
|
|
74e3f90…
|
drh
|
1872 |
/* |
|
109d8f5…
|
mistachkin
|
1873 |
** TH1 command: randhex N |
|
74e3f90…
|
drh
|
1874 |
** |
|
b000db4…
|
mistachkin
|
1875 |
** Return N*2 random hexadecimal digits with N<50. If N is omitted, |
|
74e3f90…
|
drh
|
1876 |
** use a value of 10. |
|
74e3f90…
|
drh
|
1877 |
*/ |
|
74e3f90…
|
drh
|
1878 |
static int randhexCmd( |
|
74e3f90…
|
drh
|
1879 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
1880 |
void *p, |
|
b000db4…
|
mistachkin
|
1881 |
int argc, |
|
b000db4…
|
mistachkin
|
1882 |
const char **argv, |
|
74e3f90…
|
drh
|
1883 |
int *argl |
|
74e3f90…
|
drh
|
1884 |
){ |
|
74e3f90…
|
drh
|
1885 |
int n; |
|
fc5a217…
|
mistachkin
|
1886 |
unsigned char aRand[50]; |
|
fc5a217…
|
mistachkin
|
1887 |
unsigned char zOut[100]; |
|
74e3f90…
|
drh
|
1888 |
if( argc!=1 && argc!=2 ){ |
|
74e3f90…
|
drh
|
1889 |
return Th_WrongNumArgs(interp, "repository ?BOOLEAN?"); |
|
74e3f90…
|
drh
|
1890 |
} |
|
74e3f90…
|
drh
|
1891 |
if( argc==2 ){ |
|
74e3f90…
|
drh
|
1892 |
if( Th_ToInt(interp, argv[1], argl[1], &n) ){ |
|
74e3f90…
|
drh
|
1893 |
return TH_ERROR; |
|
74e3f90…
|
drh
|
1894 |
} |
|
74e3f90…
|
drh
|
1895 |
if( n<1 ) n = 1; |
|
53db40e…
|
drh
|
1896 |
if( n>(int)sizeof(aRand) ) n = sizeof(aRand); |
|
74e3f90…
|
drh
|
1897 |
}else{ |
|
74e3f90…
|
drh
|
1898 |
n = 10; |
|
74e3f90…
|
drh
|
1899 |
} |
|
74e3f90…
|
drh
|
1900 |
sqlite3_randomness(n, aRand); |
|
74e3f90…
|
drh
|
1901 |
encode16(aRand, zOut, n); |
|
fc5a217…
|
mistachkin
|
1902 |
Th_SetResult(interp, (const char *)zOut, -1); |
|
74e3f90…
|
drh
|
1903 |
return TH_OK; |
|
801eca6…
|
drh
|
1904 |
} |
|
801eca6…
|
drh
|
1905 |
|
|
801eca6…
|
drh
|
1906 |
/* |
|
801eca6…
|
drh
|
1907 |
** Run sqlite3_step() while suppressing error messages sent to the |
|
801eca6…
|
drh
|
1908 |
** rendered webpage or to the console. |
|
801eca6…
|
drh
|
1909 |
*/ |
|
801eca6…
|
drh
|
1910 |
static int ignore_errors_step(sqlite3_stmt *pStmt){ |
|
801eca6…
|
drh
|
1911 |
int rc; |
|
801eca6…
|
drh
|
1912 |
g.dbIgnoreErrors++; |
|
801eca6…
|
drh
|
1913 |
rc = sqlite3_step(pStmt); |
|
801eca6…
|
drh
|
1914 |
g.dbIgnoreErrors--; |
|
801eca6…
|
drh
|
1915 |
return rc; |
|
c8289bd…
|
drh
|
1916 |
} |
|
c8289bd…
|
drh
|
1917 |
|
|
c8289bd…
|
drh
|
1918 |
/* |
|
c8289bd…
|
drh
|
1919 |
** TH1 command: query [-nocomplain] SQL CODE |
|
4f8c897…
|
drh
|
1920 |
** |
|
4f8c897…
|
drh
|
1921 |
** Run the SQL query given by the SQL argument. For each row in the result |
|
4f8c897…
|
drh
|
1922 |
** set, run CODE. |
|
4f8c897…
|
drh
|
1923 |
** |
|
4f8c897…
|
drh
|
1924 |
** In SQL, parameters such as $var are filled in using the value of variable |
|
4f8c897…
|
drh
|
1925 |
** "var". Result values are stored in variables with the column name prior |
|
4f8c897…
|
drh
|
1926 |
** to each invocation of CODE. |
|
4f8c897…
|
drh
|
1927 |
*/ |
|
4f8c897…
|
drh
|
1928 |
static int queryCmd( |
|
4f8c897…
|
drh
|
1929 |
Th_Interp *interp, |
|
b000db4…
|
mistachkin
|
1930 |
void *p, |
|
b000db4…
|
mistachkin
|
1931 |
int argc, |
|
b000db4…
|
mistachkin
|
1932 |
const char **argv, |
|
4f8c897…
|
drh
|
1933 |
int *argl |
|
4f8c897…
|
drh
|
1934 |
){ |
|
4f8c897…
|
drh
|
1935 |
sqlite3_stmt *pStmt; |
|
4f8c897…
|
drh
|
1936 |
int rc; |
|
4f8c897…
|
drh
|
1937 |
const char *zSql; |
|
4f8c897…
|
drh
|
1938 |
int nSql; |
|
4f8c897…
|
drh
|
1939 |
const char *zTail; |
|
4f8c897…
|
drh
|
1940 |
int n, i; |
|
4f8c897…
|
drh
|
1941 |
int res = TH_OK; |
|
4f8c897…
|
drh
|
1942 |
int nVar; |
|
2056f62…
|
drh
|
1943 |
char *zErr = 0; |
|
c8289bd…
|
drh
|
1944 |
int noComplain = 0; |
|
4f8c897…
|
drh
|
1945 |
|
|
2116238…
|
drh
|
1946 |
if( argc>3 && TH1_LEN(argl[1])==11 |
|
2116238…
|
drh
|
1947 |
&& strncmp(argv[1], "-nocomplain", 11)==0 |
|
2116238…
|
drh
|
1948 |
){ |
|
c8289bd…
|
drh
|
1949 |
argc--; |
|
c8289bd…
|
drh
|
1950 |
argv++; |
|
c8289bd…
|
drh
|
1951 |
argl++; |
|
c8289bd…
|
drh
|
1952 |
noComplain = 1; |
|
c8289bd…
|
drh
|
1953 |
} |
|
4f8c897…
|
drh
|
1954 |
if( argc!=3 ){ |
|
4f8c897…
|
drh
|
1955 |
return Th_WrongNumArgs(interp, "query SQL CODE"); |
|
4f8c897…
|
drh
|
1956 |
} |
|
4f8c897…
|
drh
|
1957 |
if( g.db==0 ){ |
|
c8289bd…
|
drh
|
1958 |
if( noComplain ) return TH_OK; |
|
4f8c897…
|
drh
|
1959 |
Th_ErrorMessage(interp, "database is not open", 0, 0); |
|
4f8c897…
|
drh
|
1960 |
return TH_ERROR; |
|
4f8c897…
|
drh
|
1961 |
} |
|
4f8c897…
|
drh
|
1962 |
zSql = argv[1]; |
|
4f8c897…
|
drh
|
1963 |
nSql = argl[1]; |
|
2116238…
|
drh
|
1964 |
if( TH1_TAINTED(nSql) ){ |
|
2116238…
|
drh
|
1965 |
if( Th_ReportTaint(interp,"query SQL",zSql,nSql) ){ |
|
2116238…
|
drh
|
1966 |
return TH_ERROR; |
|
2116238…
|
drh
|
1967 |
} |
|
2116238…
|
drh
|
1968 |
nSql = TH1_LEN(nSql); |
|
2116238…
|
drh
|
1969 |
} |
|
2116238…
|
drh
|
1970 |
|
|
4f8c897…
|
drh
|
1971 |
while( res==TH_OK && nSql>0 ){ |
|
2056f62…
|
drh
|
1972 |
zErr = 0; |
|
3071475…
|
drh
|
1973 |
report_restrict_sql(&zErr); |
|
801eca6…
|
drh
|
1974 |
g.dbIgnoreErrors++; |
|
2116238…
|
drh
|
1975 |
rc = sqlite3_prepare_v2(g.db, argv[1], TH1_LEN(argl[1]), &pStmt, &zTail); |
|
801eca6…
|
drh
|
1976 |
g.dbIgnoreErrors--; |
|
3071475…
|
drh
|
1977 |
report_unrestrict_sql(); |
|
2056f62…
|
drh
|
1978 |
if( rc!=0 || zErr!=0 ){ |
|
c8289bd…
|
drh
|
1979 |
if( noComplain ) return TH_OK; |
|
2056f62…
|
drh
|
1980 |
Th_ErrorMessage(interp, "SQL error: ", |
|
2056f62…
|
drh
|
1981 |
zErr ? zErr : sqlite3_errmsg(g.db), -1); |
|
4f8c897…
|
drh
|
1982 |
return TH_ERROR; |
|
4f8c897…
|
drh
|
1983 |
} |
|
4f8c897…
|
drh
|
1984 |
n = (int)(zTail - zSql); |
|
4f8c897…
|
drh
|
1985 |
zSql += n; |
|
4f8c897…
|
drh
|
1986 |
nSql -= n; |
|
4f8c897…
|
drh
|
1987 |
if( pStmt==0 ) continue; |
|
4f8c897…
|
drh
|
1988 |
nVar = sqlite3_bind_parameter_count(pStmt); |
|
4f8c897…
|
drh
|
1989 |
for(i=1; i<=nVar; i++){ |
|
4f8c897…
|
drh
|
1990 |
const char *zVar = sqlite3_bind_parameter_name(pStmt, i); |
|
4f8c897…
|
drh
|
1991 |
int szVar = zVar ? th_strlen(zVar) : 0; |
|
4f8c897…
|
drh
|
1992 |
if( szVar>1 && zVar[0]=='$' |
|
4f8c897…
|
drh
|
1993 |
&& Th_GetVar(interp, zVar+1, szVar-1)==TH_OK ){ |
|
4f8c897…
|
drh
|
1994 |
int nVal; |
|
4f8c897…
|
drh
|
1995 |
const char *zVal = Th_GetResult(interp, &nVal); |
|
2116238…
|
drh
|
1996 |
sqlite3_bind_text(pStmt, i, zVal, TH1_LEN(nVal), SQLITE_TRANSIENT); |
|
4f8c897…
|
drh
|
1997 |
} |
|
4f8c897…
|
drh
|
1998 |
} |
|
801eca6…
|
drh
|
1999 |
while( res==TH_OK && ignore_errors_step(pStmt)==SQLITE_ROW ){ |
|
4f8c897…
|
drh
|
2000 |
int nCol = sqlite3_column_count(pStmt); |
|
4f8c897…
|
drh
|
2001 |
for(i=0; i<nCol; i++){ |
|
4f8c897…
|
drh
|
2002 |
const char *zCol = sqlite3_column_name(pStmt, i); |
|
4f8c897…
|
drh
|
2003 |
int szCol = th_strlen(zCol); |
|
4f8c897…
|
drh
|
2004 |
const char *zVal = (const char*)sqlite3_column_text(pStmt, i); |
|
4f8c897…
|
drh
|
2005 |
int szVal = sqlite3_column_bytes(pStmt, i); |
|
2116238…
|
drh
|
2006 |
Th_SetVar(interp, zCol, szCol, zVal, TH1_ADD_TAINT(szVal)); |
|
fee9ede…
|
mistachkin
|
2007 |
} |
|
fee9ede…
|
mistachkin
|
2008 |
if( g.thTrace ){ |
|
2116238…
|
drh
|
2009 |
Th_Trace("query_eval {<pre>%#h</pre>}<br>\n",TH1_LEN(argl[2]),argv[2]); |
|
4f8c897…
|
drh
|
2010 |
} |
|
2116238…
|
drh
|
2011 |
res = Th_Eval(interp, 0, argv[2], TH1_LEN(argl[2])); |
|
fee9ede…
|
mistachkin
|
2012 |
if( g.thTrace ){ |
|
fee9ede…
|
mistachkin
|
2013 |
int nTrRes; |
|
fee9ede…
|
mistachkin
|
2014 |
char *zTrRes = (char*)Th_GetResult(g.interp, &nTrRes); |
|
f5482a0…
|
wyoung
|
2015 |
Th_Trace("[query_eval] => %h {%#h}<br>\n", |
|
2116238…
|
drh
|
2016 |
Th_ReturnCodeName(res, 0), TH1_LEN(nTrRes), zTrRes); |
|
fee9ede…
|
mistachkin
|
2017 |
} |
|
4f8c897…
|
drh
|
2018 |
if( res==TH_BREAK || res==TH_CONTINUE ) res = TH_OK; |
|
4f8c897…
|
drh
|
2019 |
} |
|
4f8c897…
|
drh
|
2020 |
rc = sqlite3_finalize(pStmt); |
|
4f8c897…
|
drh
|
2021 |
if( rc!=SQLITE_OK ){ |
|
c8289bd…
|
drh
|
2022 |
if( noComplain ) return TH_OK; |
|
4f8c897…
|
drh
|
2023 |
Th_ErrorMessage(interp, "SQL error: ", sqlite3_errmsg(g.db), -1); |
|
4f8c897…
|
drh
|
2024 |
return TH_ERROR; |
|
4f8c897…
|
drh
|
2025 |
} |
|
b000db4…
|
mistachkin
|
2026 |
} |
|
4f8c897…
|
drh
|
2027 |
return res; |
|
d772ff7…
|
mistachkin
|
2028 |
} |
|
d772ff7…
|
mistachkin
|
2029 |
|
|
d772ff7…
|
mistachkin
|
2030 |
/* |
|
109d8f5…
|
mistachkin
|
2031 |
** TH1 command: setting name |
|
0264475…
|
mistachkin
|
2032 |
** |
|
0264475…
|
mistachkin
|
2033 |
** Gets and returns the value of the specified Fossil setting. |
|
0264475…
|
mistachkin
|
2034 |
*/ |
|
0264475…
|
mistachkin
|
2035 |
#define SETTING_WRONGNUMARGS "setting ?-strict? ?--? name" |
|
0264475…
|
mistachkin
|
2036 |
static int settingCmd( |
|
0264475…
|
mistachkin
|
2037 |
Th_Interp *interp, |
|
0264475…
|
mistachkin
|
2038 |
void *p, |
|
0264475…
|
mistachkin
|
2039 |
int argc, |
|
0264475…
|
mistachkin
|
2040 |
const char **argv, |
|
0264475…
|
mistachkin
|
2041 |
int *argl |
|
0264475…
|
mistachkin
|
2042 |
){ |
|
0264475…
|
mistachkin
|
2043 |
int rc; |
|
0264475…
|
mistachkin
|
2044 |
int strict = 0; |
|
0264475…
|
mistachkin
|
2045 |
int nArg = 1; |
|
0264475…
|
mistachkin
|
2046 |
char *zValue; |
|
0264475…
|
mistachkin
|
2047 |
if( argc<2 || argc>4 ){ |
|
0264475…
|
mistachkin
|
2048 |
return Th_WrongNumArgs(interp, SETTING_WRONGNUMARGS); |
|
0264475…
|
mistachkin
|
2049 |
} |
|
0264475…
|
mistachkin
|
2050 |
if( fossil_strcmp(argv[nArg], "-strict")==0 ){ |
|
0264475…
|
mistachkin
|
2051 |
strict = 1; nArg++; |
|
0264475…
|
mistachkin
|
2052 |
} |
|
0264475…
|
mistachkin
|
2053 |
if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++; |
|
0264475…
|
mistachkin
|
2054 |
if( nArg+1!=argc ){ |
|
0264475…
|
mistachkin
|
2055 |
return Th_WrongNumArgs(interp, SETTING_WRONGNUMARGS); |
|
0264475…
|
mistachkin
|
2056 |
} |
|
0264475…
|
mistachkin
|
2057 |
zValue = db_get(argv[nArg], 0); |
|
0264475…
|
mistachkin
|
2058 |
if( zValue!=0 ){ |
|
0264475…
|
mistachkin
|
2059 |
Th_SetResult(interp, zValue, -1); |
|
0264475…
|
mistachkin
|
2060 |
rc = TH_OK; |
|
0264475…
|
mistachkin
|
2061 |
}else if( strict ){ |
|
0264475…
|
mistachkin
|
2062 |
Th_ErrorMessage(interp, "no value for setting \"", argv[nArg], -1); |
|
0264475…
|
mistachkin
|
2063 |
rc = TH_ERROR; |
|
0264475…
|
mistachkin
|
2064 |
}else{ |
|
0264475…
|
mistachkin
|
2065 |
Th_SetResult(interp, 0, 0); |
|
0264475…
|
mistachkin
|
2066 |
rc = TH_OK; |
|
0264475…
|
mistachkin
|
2067 |
} |
|
0264475…
|
mistachkin
|
2068 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
2069 |
Th_Trace("[setting %s%#h] => %d<br>\n", strict ? "strict " : "", |
|
2116238…
|
drh
|
2070 |
TH1_LEN(argl[nArg]), argv[nArg], rc); |
|
62f1f48…
|
mistachkin
|
2071 |
} |
|
62f1f48…
|
mistachkin
|
2072 |
return rc; |
|
62f1f48…
|
mistachkin
|
2073 |
} |
|
62f1f48…
|
mistachkin
|
2074 |
|
|
62f1f48…
|
mistachkin
|
2075 |
/* |
|
62f1f48…
|
mistachkin
|
2076 |
** TH1 command: glob_match ?-one? ?--? patternList string |
|
62f1f48…
|
mistachkin
|
2077 |
** |
|
62f1f48…
|
mistachkin
|
2078 |
** Checks the string against the specified glob pattern -OR- list of glob |
|
62f1f48…
|
mistachkin
|
2079 |
** patterns and returns non-zero if there is a match. |
|
62f1f48…
|
mistachkin
|
2080 |
*/ |
|
62f1f48…
|
mistachkin
|
2081 |
#define GLOB_MATCH_WRONGNUMARGS "glob_match ?-one? ?--? patternList string" |
|
62f1f48…
|
mistachkin
|
2082 |
static int globMatchCmd( |
|
62f1f48…
|
mistachkin
|
2083 |
Th_Interp *interp, |
|
62f1f48…
|
mistachkin
|
2084 |
void *p, |
|
62f1f48…
|
mistachkin
|
2085 |
int argc, |
|
62f1f48…
|
mistachkin
|
2086 |
const char **argv, |
|
62f1f48…
|
mistachkin
|
2087 |
int *argl |
|
62f1f48…
|
mistachkin
|
2088 |
){ |
|
62f1f48…
|
mistachkin
|
2089 |
int rc; |
|
62f1f48…
|
mistachkin
|
2090 |
int one = 0; |
|
62f1f48…
|
mistachkin
|
2091 |
int nArg = 1; |
|
62f1f48…
|
mistachkin
|
2092 |
Glob *pGlob = 0; |
|
62f1f48…
|
mistachkin
|
2093 |
if( argc<3 || argc>5 ){ |
|
62f1f48…
|
mistachkin
|
2094 |
return Th_WrongNumArgs(interp, GLOB_MATCH_WRONGNUMARGS); |
|
62f1f48…
|
mistachkin
|
2095 |
} |
|
62f1f48…
|
mistachkin
|
2096 |
if( fossil_strcmp(argv[nArg], "-one")==0 ){ |
|
62f1f48…
|
mistachkin
|
2097 |
one = 1; nArg++; |
|
62f1f48…
|
mistachkin
|
2098 |
} |
|
62f1f48…
|
mistachkin
|
2099 |
if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++; |
|
62f1f48…
|
mistachkin
|
2100 |
if( nArg+2!=argc ){ |
|
62f1f48…
|
mistachkin
|
2101 |
return Th_WrongNumArgs(interp, GLOB_MATCH_WRONGNUMARGS); |
|
62f1f48…
|
mistachkin
|
2102 |
} |
|
62f1f48…
|
mistachkin
|
2103 |
if( one ){ |
|
62f1f48…
|
mistachkin
|
2104 |
Th_SetResultInt(interp, sqlite3_strglob(argv[nArg], argv[nArg+1])==0); |
|
62f1f48…
|
mistachkin
|
2105 |
rc = TH_OK; |
|
62f1f48…
|
mistachkin
|
2106 |
}else{ |
|
62f1f48…
|
mistachkin
|
2107 |
pGlob = glob_create(argv[nArg]); |
|
62f1f48…
|
mistachkin
|
2108 |
if( pGlob ){ |
|
62f1f48…
|
mistachkin
|
2109 |
Th_SetResultInt(interp, glob_match(pGlob, argv[nArg+1])); |
|
62f1f48…
|
mistachkin
|
2110 |
rc = TH_OK; |
|
62f1f48…
|
mistachkin
|
2111 |
}else{ |
|
62f1f48…
|
mistachkin
|
2112 |
Th_SetResult(interp, "unable to create glob from pattern list", -1); |
|
62f1f48…
|
mistachkin
|
2113 |
rc = TH_ERROR; |
|
62f1f48…
|
mistachkin
|
2114 |
} |
|
62f1f48…
|
mistachkin
|
2115 |
glob_free(pGlob); |
|
0264475…
|
mistachkin
|
2116 |
} |
|
0264475…
|
mistachkin
|
2117 |
return rc; |
|
0264475…
|
mistachkin
|
2118 |
} |
|
0264475…
|
mistachkin
|
2119 |
|
|
0264475…
|
mistachkin
|
2120 |
/* |
|
109d8f5…
|
mistachkin
|
2121 |
** TH1 command: regexp ?-nocase? ?--? exp string |
|
d772ff7…
|
mistachkin
|
2122 |
** |
|
d772ff7…
|
mistachkin
|
2123 |
** Checks the string against the specified regular expression and returns |
|
d772ff7…
|
mistachkin
|
2124 |
** non-zero if it matches. If the regular expression is invalid or cannot |
|
d772ff7…
|
mistachkin
|
2125 |
** be compiled, an error will be generated. |
|
d772ff7…
|
mistachkin
|
2126 |
*/ |
|
d772ff7…
|
mistachkin
|
2127 |
#define REGEXP_WRONGNUMARGS "regexp ?-nocase? ?--? exp string" |
|
d772ff7…
|
mistachkin
|
2128 |
static int regexpCmd( |
|
d772ff7…
|
mistachkin
|
2129 |
Th_Interp *interp, |
|
d772ff7…
|
mistachkin
|
2130 |
void *p, |
|
d772ff7…
|
mistachkin
|
2131 |
int argc, |
|
d772ff7…
|
mistachkin
|
2132 |
const char **argv, |
|
d772ff7…
|
mistachkin
|
2133 |
int *argl |
|
d772ff7…
|
mistachkin
|
2134 |
){ |
|
d772ff7…
|
mistachkin
|
2135 |
int rc; |
|
d772ff7…
|
mistachkin
|
2136 |
int noCase = 0; |
|
d772ff7…
|
mistachkin
|
2137 |
int nArg = 1; |
|
d772ff7…
|
mistachkin
|
2138 |
ReCompiled *pRe = 0; |
|
d772ff7…
|
mistachkin
|
2139 |
const char *zErr; |
|
d772ff7…
|
mistachkin
|
2140 |
if( argc<3 || argc>5 ){ |
|
d772ff7…
|
mistachkin
|
2141 |
return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS); |
|
d772ff7…
|
mistachkin
|
2142 |
} |
|
d772ff7…
|
mistachkin
|
2143 |
if( fossil_strcmp(argv[nArg], "-nocase")==0 ){ |
|
d772ff7…
|
mistachkin
|
2144 |
noCase = 1; nArg++; |
|
d772ff7…
|
mistachkin
|
2145 |
} |
|
d772ff7…
|
mistachkin
|
2146 |
if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++; |
|
d772ff7…
|
mistachkin
|
2147 |
if( nArg+2!=argc ){ |
|
d772ff7…
|
mistachkin
|
2148 |
return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS); |
|
d772ff7…
|
mistachkin
|
2149 |
} |
|
82888a0…
|
drh
|
2150 |
zErr = fossil_re_compile(&pRe, argv[nArg], noCase); |
|
d772ff7…
|
mistachkin
|
2151 |
if( !zErr ){ |
|
d772ff7…
|
mistachkin
|
2152 |
Th_SetResultInt(interp, re_match(pRe, |
|
2116238…
|
drh
|
2153 |
(const unsigned char *)argv[nArg+1], TH1_LEN(argl[nArg+1]))); |
|
d772ff7…
|
mistachkin
|
2154 |
rc = TH_OK; |
|
d772ff7…
|
mistachkin
|
2155 |
}else{ |
|
d772ff7…
|
mistachkin
|
2156 |
Th_SetResult(interp, zErr, -1); |
|
d772ff7…
|
mistachkin
|
2157 |
rc = TH_ERROR; |
|
d772ff7…
|
mistachkin
|
2158 |
} |
|
d772ff7…
|
mistachkin
|
2159 |
re_free(pRe); |
|
d772ff7…
|
mistachkin
|
2160 |
return rc; |
|
1311841…
|
jan.nijtmans
|
2161 |
} |
|
1311841…
|
jan.nijtmans
|
2162 |
|
|
1311841…
|
jan.nijtmans
|
2163 |
/* |
|
109d8f5…
|
mistachkin
|
2164 |
** TH1 command: http ?-asynchronous? ?--? url ?payload? |
|
1311841…
|
jan.nijtmans
|
2165 |
** |
|
1311841…
|
jan.nijtmans
|
2166 |
** Perform an HTTP or HTTPS request for the specified URL. If a |
|
1311841…
|
jan.nijtmans
|
2167 |
** payload is present, it will be interpreted as text/plain and |
|
1311841…
|
jan.nijtmans
|
2168 |
** the POST method will be used; otherwise, the GET method will |
|
1311841…
|
jan.nijtmans
|
2169 |
** be used. Upon success, if the -asynchronous option is used, an |
|
1311841…
|
jan.nijtmans
|
2170 |
** empty string is returned as the result; otherwise, the response |
|
1311841…
|
jan.nijtmans
|
2171 |
** from the server is returned as the result. Synchronous requests |
|
1311841…
|
jan.nijtmans
|
2172 |
** are not currently implemented. |
|
1311841…
|
jan.nijtmans
|
2173 |
*/ |
|
1311841…
|
jan.nijtmans
|
2174 |
#define HTTP_WRONGNUMARGS "http ?-asynchronous? ?--? url ?payload?" |
|
1311841…
|
jan.nijtmans
|
2175 |
static int httpCmd( |
|
1311841…
|
jan.nijtmans
|
2176 |
Th_Interp *interp, |
|
1311841…
|
jan.nijtmans
|
2177 |
void *p, |
|
1311841…
|
jan.nijtmans
|
2178 |
int argc, |
|
1311841…
|
jan.nijtmans
|
2179 |
const char **argv, |
|
1311841…
|
jan.nijtmans
|
2180 |
int *argl |
|
1311841…
|
jan.nijtmans
|
2181 |
){ |
|
1311841…
|
jan.nijtmans
|
2182 |
int nArg = 1; |
|
1311841…
|
jan.nijtmans
|
2183 |
int fAsynchronous = 0; |
|
1311841…
|
jan.nijtmans
|
2184 |
const char *zType, *zRegexp; |
|
1311841…
|
jan.nijtmans
|
2185 |
Blob payload; |
|
1311841…
|
jan.nijtmans
|
2186 |
ReCompiled *pRe = 0; |
|
1311841…
|
jan.nijtmans
|
2187 |
UrlData urlData; |
|
1311841…
|
jan.nijtmans
|
2188 |
|
|
1311841…
|
jan.nijtmans
|
2189 |
if( argc<2 || argc>5 ){ |
|
1311841…
|
jan.nijtmans
|
2190 |
return Th_WrongNumArgs(interp, HTTP_WRONGNUMARGS); |
|
1311841…
|
jan.nijtmans
|
2191 |
} |
|
2116238…
|
drh
|
2192 |
if( fossil_strnicmp(argv[nArg], "-asynchronous", TH1_LEN(argl[nArg]))==0 ){ |
|
1311841…
|
jan.nijtmans
|
2193 |
fAsynchronous = 1; nArg++; |
|
1311841…
|
jan.nijtmans
|
2194 |
} |
|
1311841…
|
jan.nijtmans
|
2195 |
if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++; |
|
1311841…
|
jan.nijtmans
|
2196 |
if( nArg+1!=argc && nArg+2!=argc ){ |
|
1311841…
|
jan.nijtmans
|
2197 |
return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS); |
|
1311841…
|
jan.nijtmans
|
2198 |
} |
|
1311841…
|
jan.nijtmans
|
2199 |
memset(&urlData, '\0', sizeof(urlData)); |
|
1311841…
|
jan.nijtmans
|
2200 |
url_parse_local(argv[nArg], 0, &urlData); |
|
1311841…
|
jan.nijtmans
|
2201 |
if( urlData.isSsh || urlData.isFile ){ |
|
1311841…
|
jan.nijtmans
|
2202 |
Th_ErrorMessage(interp, "url must be http:// or https://", 0, 0); |
|
1311841…
|
jan.nijtmans
|
2203 |
return TH_ERROR; |
|
1311841…
|
jan.nijtmans
|
2204 |
} |
|
1311841…
|
jan.nijtmans
|
2205 |
zRegexp = db_get("th1-uri-regexp", 0); |
|
1311841…
|
jan.nijtmans
|
2206 |
if( zRegexp && zRegexp[0] ){ |
|
82888a0…
|
drh
|
2207 |
const char *zErr = fossil_re_compile(&pRe, zRegexp, 0); |
|
1311841…
|
jan.nijtmans
|
2208 |
if( zErr ){ |
|
1311841…
|
jan.nijtmans
|
2209 |
Th_SetResult(interp, zErr, -1); |
|
1311841…
|
jan.nijtmans
|
2210 |
return TH_ERROR; |
|
1311841…
|
jan.nijtmans
|
2211 |
} |
|
1311841…
|
jan.nijtmans
|
2212 |
} |
|
1311841…
|
jan.nijtmans
|
2213 |
if( !pRe || !re_match(pRe, (const unsigned char *)urlData.canonical, -1) ){ |
|
1311841…
|
jan.nijtmans
|
2214 |
Th_SetResult(interp, "url not allowed", -1); |
|
1311841…
|
jan.nijtmans
|
2215 |
re_free(pRe); |
|
1311841…
|
jan.nijtmans
|
2216 |
return TH_ERROR; |
|
1311841…
|
jan.nijtmans
|
2217 |
} |
|
1311841…
|
jan.nijtmans
|
2218 |
re_free(pRe); |
|
1311841…
|
jan.nijtmans
|
2219 |
blob_zero(&payload); |
|
1311841…
|
jan.nijtmans
|
2220 |
if( nArg+2==argc ){ |
|
2116238…
|
drh
|
2221 |
blob_append(&payload, argv[nArg+1], TH1_LEN(argl[nArg+1])); |
|
1311841…
|
jan.nijtmans
|
2222 |
zType = "POST"; |
|
1311841…
|
jan.nijtmans
|
2223 |
}else{ |
|
1311841…
|
jan.nijtmans
|
2224 |
zType = "GET"; |
|
1311841…
|
jan.nijtmans
|
2225 |
} |
|
1311841…
|
jan.nijtmans
|
2226 |
if( fAsynchronous ){ |
|
1311841…
|
jan.nijtmans
|
2227 |
const char *zSep, *zParams; |
|
1311841…
|
jan.nijtmans
|
2228 |
Blob hdr; |
|
1311841…
|
jan.nijtmans
|
2229 |
zParams = strrchr(argv[nArg], '?'); |
|
1311841…
|
jan.nijtmans
|
2230 |
if( strlen(urlData.path)>0 && zParams!=argv[nArg] ){ |
|
1311841…
|
jan.nijtmans
|
2231 |
zSep = ""; |
|
1311841…
|
jan.nijtmans
|
2232 |
}else{ |
|
1311841…
|
jan.nijtmans
|
2233 |
zSep = "/"; |
|
1311841…
|
jan.nijtmans
|
2234 |
} |
|
1311841…
|
jan.nijtmans
|
2235 |
blob_zero(&hdr); |
|
1311841…
|
jan.nijtmans
|
2236 |
blob_appendf(&hdr, "%s %s%s%s HTTP/1.0\r\n", |
|
1311841…
|
jan.nijtmans
|
2237 |
zType, zSep, urlData.path, zParams ? zParams : ""); |
|
1311841…
|
jan.nijtmans
|
2238 |
if( urlData.proxyAuth ){ |
|
1311841…
|
jan.nijtmans
|
2239 |
blob_appendf(&hdr, "Proxy-Authorization: %s\r\n", urlData.proxyAuth); |
|
1311841…
|
jan.nijtmans
|
2240 |
} |
|
1311841…
|
jan.nijtmans
|
2241 |
if( urlData.passwd && urlData.user && urlData.passwd[0]=='#' ){ |
|
1311841…
|
jan.nijtmans
|
2242 |
char *zCredentials = mprintf("%s:%s", urlData.user, &urlData.passwd[1]); |
|
1311841…
|
jan.nijtmans
|
2243 |
char *zEncoded = encode64(zCredentials, -1); |
|
1311841…
|
jan.nijtmans
|
2244 |
blob_appendf(&hdr, "Authorization: Basic %s\r\n", zEncoded); |
|
1311841…
|
jan.nijtmans
|
2245 |
fossil_free(zEncoded); |
|
1311841…
|
jan.nijtmans
|
2246 |
fossil_free(zCredentials); |
|
1311841…
|
jan.nijtmans
|
2247 |
} |
|
1311841…
|
jan.nijtmans
|
2248 |
blob_appendf(&hdr, "Host: %s\r\n" |
|
1311841…
|
jan.nijtmans
|
2249 |
"User-Agent: %s\r\n", urlData.hostname, get_user_agent()); |
|
1311841…
|
jan.nijtmans
|
2250 |
if( zType[0]=='P' ){ |
|
1311841…
|
jan.nijtmans
|
2251 |
blob_appendf(&hdr, "Content-Type: application/x-www-form-urlencoded\r\n" |
|
1311841…
|
jan.nijtmans
|
2252 |
"Content-Length: %d\r\n\r\n", blob_size(&payload)); |
|
1311841…
|
jan.nijtmans
|
2253 |
}else{ |
|
1311841…
|
jan.nijtmans
|
2254 |
blob_appendf(&hdr, "\r\n"); |
|
1311841…
|
jan.nijtmans
|
2255 |
} |
|
1311841…
|
jan.nijtmans
|
2256 |
if( transport_open(&urlData) ){ |
|
1311841…
|
jan.nijtmans
|
2257 |
Th_ErrorMessage(interp, transport_errmsg(&urlData), 0, 0); |
|
1311841…
|
jan.nijtmans
|
2258 |
blob_reset(&hdr); |
|
1311841…
|
jan.nijtmans
|
2259 |
blob_reset(&payload); |
|
1311841…
|
jan.nijtmans
|
2260 |
return TH_ERROR; |
|
1311841…
|
jan.nijtmans
|
2261 |
} |
|
1311841…
|
jan.nijtmans
|
2262 |
transport_send(&urlData, &hdr); |
|
1311841…
|
jan.nijtmans
|
2263 |
transport_send(&urlData, &payload); |
|
1311841…
|
jan.nijtmans
|
2264 |
blob_reset(&hdr); |
|
1311841…
|
jan.nijtmans
|
2265 |
blob_reset(&payload); |
|
1311841…
|
jan.nijtmans
|
2266 |
transport_close(&urlData); |
|
1311841…
|
jan.nijtmans
|
2267 |
Th_SetResult(interp, 0, 0); /* NOTE: Asynchronous, no results. */ |
|
1311841…
|
jan.nijtmans
|
2268 |
return TH_OK; |
|
1311841…
|
jan.nijtmans
|
2269 |
}else{ |
|
1311841…
|
jan.nijtmans
|
2270 |
Th_ErrorMessage(interp, |
|
1311841…
|
jan.nijtmans
|
2271 |
"synchronous requests are not yet implemented", 0, 0); |
|
1311841…
|
jan.nijtmans
|
2272 |
blob_reset(&payload); |
|
1311841…
|
jan.nijtmans
|
2273 |
return TH_ERROR; |
|
1311841…
|
jan.nijtmans
|
2274 |
} |
|
1311841…
|
jan.nijtmans
|
2275 |
} |
|
5173701…
|
stephan
|
2276 |
|
|
5173701…
|
stephan
|
2277 |
/* |
|
5173701…
|
stephan
|
2278 |
** TH1 command: captureTh1 STRING |
|
5173701…
|
stephan
|
2279 |
** |
|
5173701…
|
stephan
|
2280 |
** Evaluates the given string as TH1 code and captures any of its |
|
5173701…
|
stephan
|
2281 |
** TH1-generated output as a string (instead of it being output), |
|
5173701…
|
stephan
|
2282 |
** which becomes the result of the function. |
|
5173701…
|
stephan
|
2283 |
*/ |
|
5173701…
|
stephan
|
2284 |
static int captureTh1Cmd( |
|
5173701…
|
stephan
|
2285 |
Th_Interp *interp, |
|
5173701…
|
stephan
|
2286 |
void *pConvert, |
|
5173701…
|
stephan
|
2287 |
int argc, |
|
5173701…
|
stephan
|
2288 |
const char **argv, |
|
5173701…
|
stephan
|
2289 |
int *argl |
|
5173701…
|
stephan
|
2290 |
){ |
|
5173701…
|
stephan
|
2291 |
Blob out = empty_blob; |
|
5173701…
|
stephan
|
2292 |
Blob * pOrig; |
|
5173701…
|
stephan
|
2293 |
const char * zStr; |
|
5173701…
|
stephan
|
2294 |
int nStr, rc; |
|
5173701…
|
stephan
|
2295 |
if( argc!=2 ){ |
|
5173701…
|
stephan
|
2296 |
return Th_WrongNumArgs(interp, "captureTh1 STRING"); |
|
5173701…
|
stephan
|
2297 |
} |
|
5173701…
|
stephan
|
2298 |
pOrig = Th_SetOutputBlob(&out); |
|
5173701…
|
stephan
|
2299 |
zStr = argv[1]; |
|
2116238…
|
drh
|
2300 |
nStr = TH1_LEN(argl[1]); |
|
5173701…
|
stephan
|
2301 |
rc = Th_Eval(g.interp, 0, zStr, nStr); |
|
5173701…
|
stephan
|
2302 |
Th_SetOutputBlob(pOrig); |
|
5173701…
|
stephan
|
2303 |
if(0==rc){ |
|
5173701…
|
stephan
|
2304 |
Th_SetResult(g.interp, blob_str(&out), blob_size(&out)); |
|
5173701…
|
stephan
|
2305 |
} |
|
5173701…
|
stephan
|
2306 |
blob_reset(&out); |
|
5173701…
|
stephan
|
2307 |
return rc; |
|
5173701…
|
stephan
|
2308 |
} |
|
5173701…
|
stephan
|
2309 |
|
|
57d8a71…
|
mistachkin
|
2310 |
|
|
57d8a71…
|
mistachkin
|
2311 |
/* |
|
9773eba…
|
mistachkin
|
2312 |
** Attempts to open the configuration ("user") database. Optionally, also |
|
9773eba…
|
mistachkin
|
2313 |
** attempts to try to find the repository and open it. |
|
9773eba…
|
mistachkin
|
2314 |
*/ |
|
9773eba…
|
mistachkin
|
2315 |
void Th_OpenConfig( |
|
9773eba…
|
mistachkin
|
2316 |
int openRepository |
|
9773eba…
|
mistachkin
|
2317 |
){ |
|
142200b…
|
mistachkin
|
2318 |
if( openRepository && !Th_IsRepositoryOpen() ){ |
|
9773eba…
|
mistachkin
|
2319 |
db_find_and_open_repository(OPEN_ANY_SCHEMA | OPEN_OK_NOT_FOUND, 0); |
|
142200b…
|
mistachkin
|
2320 |
if( Th_IsRepositoryOpen() ){ |
|
142200b…
|
mistachkin
|
2321 |
g.th1Flags |= TH_STATE_REPOSITORY; |
|
142200b…
|
mistachkin
|
2322 |
}else{ |
|
142200b…
|
mistachkin
|
2323 |
g.th1Flags &= ~TH_STATE_REPOSITORY; |
|
142200b…
|
mistachkin
|
2324 |
} |
|
1c528d3…
|
mistachkin
|
2325 |
} |
|
142200b…
|
mistachkin
|
2326 |
if( !Th_IsConfigOpen() ){ |
|
b06cd63…
|
mistachkin
|
2327 |
db_open_config(0, 1); |
|
142200b…
|
mistachkin
|
2328 |
if( Th_IsConfigOpen() ){ |
|
142200b…
|
mistachkin
|
2329 |
g.th1Flags |= TH_STATE_CONFIG; |
|
142200b…
|
mistachkin
|
2330 |
}else{ |
|
142200b…
|
mistachkin
|
2331 |
g.th1Flags &= ~TH_STATE_CONFIG; |
|
142200b…
|
mistachkin
|
2332 |
} |
|
142200b…
|
mistachkin
|
2333 |
} |
|
1c528d3…
|
mistachkin
|
2334 |
} |
|
1c528d3…
|
mistachkin
|
2335 |
|
|
1c528d3…
|
mistachkin
|
2336 |
/* |
|
1c528d3…
|
mistachkin
|
2337 |
** Attempts to close the configuration ("user") database. Optionally, also |
|
1c528d3…
|
mistachkin
|
2338 |
** attempts to close the repository. |
|
1c528d3…
|
mistachkin
|
2339 |
*/ |
|
1c528d3…
|
mistachkin
|
2340 |
void Th_CloseConfig( |
|
1c528d3…
|
mistachkin
|
2341 |
int closeRepository |
|
1c528d3…
|
mistachkin
|
2342 |
){ |
|
142200b…
|
mistachkin
|
2343 |
if( g.th1Flags & TH_STATE_CONFIG ){ |
|
142200b…
|
mistachkin
|
2344 |
db_close_config(); |
|
142200b…
|
mistachkin
|
2345 |
g.th1Flags &= ~TH_STATE_CONFIG; |
|
142200b…
|
mistachkin
|
2346 |
} |
|
142200b…
|
mistachkin
|
2347 |
if( closeRepository && (g.th1Flags & TH_STATE_REPOSITORY) ){ |
|
1c528d3…
|
mistachkin
|
2348 |
db_close(1); |
|
142200b…
|
mistachkin
|
2349 |
g.th1Flags &= ~TH_STATE_REPOSITORY; |
|
1c528d3…
|
mistachkin
|
2350 |
} |
|
9773eba…
|
mistachkin
|
2351 |
} |
|
9773eba…
|
mistachkin
|
2352 |
|
|
9773eba…
|
mistachkin
|
2353 |
/* |
|
f55c6a1…
|
drh
|
2354 |
** Make sure the interpreter has been initialized. Initialize it if |
|
f55c6a1…
|
drh
|
2355 |
** it has not been already. |
|
f55c6a1…
|
drh
|
2356 |
** |
|
f55c6a1…
|
drh
|
2357 |
** The interpreter is stored in the g.interp global variable. |
|
588bb7c…
|
aku
|
2358 |
*/ |
|
0e68620…
|
mistachkin
|
2359 |
void Th_FossilInit(u32 flags){ |
|
b058c8a…
|
mistachkin
|
2360 |
int wasInit = 0; |
|
0e68620…
|
mistachkin
|
2361 |
int needConfig = flags & TH_INIT_NEED_CONFIG; |
|
0e68620…
|
mistachkin
|
2362 |
int forceReset = flags & TH_INIT_FORCE_RESET; |
|
0e68620…
|
mistachkin
|
2363 |
int forceTcl = flags & TH_INIT_FORCE_TCL; |
|
0e68620…
|
mistachkin
|
2364 |
int forceSetup = flags & TH_INIT_FORCE_SETUP; |
|
57d8a71…
|
mistachkin
|
2365 |
int noRepo = flags & TH_INIT_NO_REPO; |
|
5173701…
|
stephan
|
2366 |
static unsigned int aFlags[] = {0, 1, WIKI_LINKSONLY}; |
|
653dd40…
|
drh
|
2367 |
static int anonFlag = LOGIN_ANON; |
|
653dd40…
|
drh
|
2368 |
static int zeroInt = 0; |
|
588bb7c…
|
aku
|
2369 |
static struct _Command { |
|
588bb7c…
|
aku
|
2370 |
const char *zName; |
|
588bb7c…
|
aku
|
2371 |
Th_CommandProc xProc; |
|
588bb7c…
|
aku
|
2372 |
void *pContext; |
|
588bb7c…
|
aku
|
2373 |
} aCommand[] = { |
|
653dd40…
|
drh
|
2374 |
{"anoncap", hascapCmd, (void*)&anonFlag}, |
|
9b70675…
|
drh
|
2375 |
{"anycap", anycapCmd, 0}, |
|
109d8f5…
|
mistachkin
|
2376 |
{"artifact", artifactCmd, 0}, |
|
9cd7428…
|
drh
|
2377 |
{"builtin_request_js", builtinRequestJsCmd, 0}, |
|
f96de5a…
|
drh
|
2378 |
{"capexpr", capexprCmd, 0}, |
|
5173701…
|
stephan
|
2379 |
{"captureTh1", captureTh1Cmd, 0}, |
|
32c4880…
|
mistachkin
|
2380 |
{"cgiHeaderLine", cgiHeaderLineCmd, 0}, |
|
57be4d5…
|
mistachkin
|
2381 |
{"checkout", checkoutCmd, 0}, |
|
588bb7c…
|
aku
|
2382 |
{"combobox", comboboxCmd, 0}, |
|
6908832…
|
drh
|
2383 |
{"copybtn", copybtnCmd, 0}, |
|
46e6a03…
|
drh
|
2384 |
{"date", dateCmd, 0}, |
|
74e3f90…
|
drh
|
2385 |
{"decorate", wikiCmd, (void*)&aFlags[2]}, |
|
c1cb688…
|
mistachkin
|
2386 |
{"defHeader", defHeaderCmd, 0}, |
|
f4ceace…
|
mistachkin
|
2387 |
{"dir", dirCmd, 0}, |
|
74e3f90…
|
drh
|
2388 |
{"enable_output", enableOutputCmd, 0}, |
|
3f21421…
|
mistachkin
|
2389 |
{"encode64", encode64Cmd, 0}, |
|
57be4d5…
|
mistachkin
|
2390 |
{"getParameter", getParameterCmd, 0}, |
|
62f1f48…
|
mistachkin
|
2391 |
{"glob_match", globMatchCmd, 0}, |
|
66ae70a…
|
drh
|
2392 |
{"globalState", globalStateCmd, 0}, |
|
fc6bb93…
|
jan.nijtmans
|
2393 |
{"httpize", httpizeCmd, 0}, |
|
653dd40…
|
drh
|
2394 |
{"hascap", hascapCmd, (void*)&zeroInt}, |
|
74e3f90…
|
drh
|
2395 |
{"hasfeature", hasfeatureCmd, 0}, |
|
74e3f90…
|
drh
|
2396 |
{"html", putsCmd, (void*)&aFlags[0]}, |
|
74e3f90…
|
drh
|
2397 |
{"htmlize", htmlizeCmd, 0}, |
|
1311841…
|
jan.nijtmans
|
2398 |
{"http", httpCmd, 0}, |
|
f8820ef…
|
mistachkin
|
2399 |
{"insertCsrf", insertCsrfCmd, 0}, |
|
74e3f90…
|
drh
|
2400 |
{"linecount", linecntCmd, 0}, |
|
f6d29e9…
|
mistachkin
|
2401 |
{"markdown", markdownCmd, 0}, |
|
8a65cd1…
|
mistachkin
|
2402 |
{"nonce", nonceCmd, 0}, |
|
74e3f90…
|
drh
|
2403 |
{"puts", putsCmd, (void*)&aFlags[1]}, |
|
4f8c897…
|
drh
|
2404 |
{"query", queryCmd, 0}, |
|
74e3f90…
|
drh
|
2405 |
{"randhex", randhexCmd, 0}, |
|
71caba5…
|
mistachkin
|
2406 |
{"redirect", redirectCmd, 0}, |
|
d772ff7…
|
mistachkin
|
2407 |
{"regexp", regexpCmd, 0}, |
|
3355835…
|
mistachkin
|
2408 |
{"reinitialize", reinitializeCmd, 0}, |
|
57be4d5…
|
mistachkin
|
2409 |
{"render", renderCmd, 0}, |
|
d8ed5a0…
|
drh
|
2410 |
{"repository", repositoryCmd, 0}, |
|
c0c0bae…
|
drh
|
2411 |
{"searchable", searchableCmd, 0}, |
|
57be4d5…
|
mistachkin
|
2412 |
{"setParameter", setParameterCmd, 0}, |
|
0264475…
|
mistachkin
|
2413 |
{"setting", settingCmd, 0}, |
|
57be4d5…
|
mistachkin
|
2414 |
{"styleFooter", styleFooterCmd, 0}, |
|
9c88799…
|
drh
|
2415 |
{"styleHeader", styleHeaderCmd, 0}, |
|
9c88799…
|
drh
|
2416 |
{"styleScript", styleScriptCmd, 0}, |
|
71b2216…
|
george
|
2417 |
{"submenu", submenuCmd, 0}, |
|
2116238…
|
drh
|
2418 |
{"taint", taintCmd, 0}, |
|
a87eaae…
|
mistachkin
|
2419 |
{"tclReady", tclReadyCmd, 0}, |
|
57be4d5…
|
mistachkin
|
2420 |
{"trace", traceCmd, 0}, |
|
3d50bdc…
|
drh
|
2421 |
{"stime", stimeCmd, 0}, |
|
2116238…
|
drh
|
2422 |
{"untaint", untaintCmd, 0}, |
|
1b5b69f…
|
mistachkin
|
2423 |
{"unversioned", unversionedCmd, 0}, |
|
74e3f90…
|
drh
|
2424 |
{"utime", utimeCmd, 0}, |
|
f8820ef…
|
mistachkin
|
2425 |
{"verifyCsrf", verifyCsrfCmd, 0}, |
|
a470d60…
|
mistachkin
|
2426 |
{"verifyLogin", verifyLoginCmd, 0}, |
|
74e3f90…
|
drh
|
2427 |
{"wiki", wikiCmd, (void*)&aFlags[0]}, |
|
25f43cc…
|
stephan
|
2428 |
{"wiki_assoc", wikiAssocCmd, 0}, |
|
1b1fd23…
|
mistachkin
|
2429 |
{0, 0, 0} |
|
588bb7c…
|
aku
|
2430 |
}; |
|
3355835…
|
mistachkin
|
2431 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
2432 |
Th_Trace("th1-init 0x%x => 0x%x<br>\n", g.th1Flags, flags); |
|
3355835…
|
mistachkin
|
2433 |
} |
|
b058c8a…
|
mistachkin
|
2434 |
if( needConfig ){ |
|
b058c8a…
|
mistachkin
|
2435 |
/* |
|
b058c8a…
|
mistachkin
|
2436 |
** This function uses several settings which may be defined in the |
|
b058c8a…
|
mistachkin
|
2437 |
** repository and/or the global configuration. Since the caller |
|
b058c8a…
|
mistachkin
|
2438 |
** passed a non-zero value for the needConfig parameter, make sure |
|
b058c8a…
|
mistachkin
|
2439 |
** the necessary database connections are open prior to continuing. |
|
b058c8a…
|
mistachkin
|
2440 |
*/ |
|
57d8a71…
|
mistachkin
|
2441 |
Th_OpenConfig(!noRepo); |
|
b058c8a…
|
mistachkin
|
2442 |
} |
|
0e68620…
|
mistachkin
|
2443 |
if( forceReset || forceTcl || g.interp==0 ){ |
|
5d20065…
|
mistachkin
|
2444 |
int created = 0; |
|
588bb7c…
|
aku
|
2445 |
int i; |
|
5d20065…
|
mistachkin
|
2446 |
if( g.interp==0 ){ |
|
999e33c…
|
mistachkin
|
2447 |
Th_Vtab *pVtab = 0; |
|
999e33c…
|
mistachkin
|
2448 |
#if defined(TH_MEMDEBUG) |
|
999e33c…
|
mistachkin
|
2449 |
if( fossil_getenv("TH1_DELETE_INTERP")!=0 ){ |
|
999e33c…
|
mistachkin
|
2450 |
pVtab = &vtab; |
|
999e33c…
|
mistachkin
|
2451 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
2452 |
Th_Trace("th1-init MEMDEBUG ENABLED<br>\n"); |
|
999e33c…
|
mistachkin
|
2453 |
} |
|
999e33c…
|
mistachkin
|
2454 |
} |
|
999e33c…
|
mistachkin
|
2455 |
#endif |
|
999e33c…
|
mistachkin
|
2456 |
g.interp = Th_CreateInterp(pVtab); |
|
5d20065…
|
mistachkin
|
2457 |
created = 1; |
|
5d20065…
|
mistachkin
|
2458 |
} |
|
5d20065…
|
mistachkin
|
2459 |
if( forceReset || created ){ |
|
5d20065…
|
mistachkin
|
2460 |
th_register_language(g.interp); /* Basic scripting commands. */ |
|
0e68620…
|
mistachkin
|
2461 |
} |
|
d8ed5a0…
|
drh
|
2462 |
#ifdef FOSSIL_ENABLE_TCL |
|
e0f22dd…
|
mistachkin
|
2463 |
if( forceTcl || fossil_getenv("TH1_ENABLE_TCL")!=0 || |
|
e0f22dd…
|
mistachkin
|
2464 |
db_get_boolean("tcl", 0) ){ |
|
b058c8a…
|
mistachkin
|
2465 |
if( !g.tcl.setup ){ |
|
b058c8a…
|
mistachkin
|
2466 |
g.tcl.setup = db_get("tcl-setup", 0); /* Grab Tcl setup script. */ |
|
b058c8a…
|
mistachkin
|
2467 |
} |
|
d8ed5a0…
|
drh
|
2468 |
th_register_tcl(g.interp, &g.tcl); /* Tcl integration commands. */ |
|
d8ed5a0…
|
drh
|
2469 |
} |
|
d8ed5a0…
|
drh
|
2470 |
#endif |
|
3cb9ba4…
|
andygoth
|
2471 |
for(i=0; i<count(aCommand); i++){ |
|
1b1fd23…
|
mistachkin
|
2472 |
if ( !aCommand[i].zName || !aCommand[i].xProc ) continue; |
|
588bb7c…
|
aku
|
2473 |
Th_CreateCommand(g.interp, aCommand[i].zName, aCommand[i].xProc, |
|
588bb7c…
|
aku
|
2474 |
aCommand[i].pContext, 0); |
|
588bb7c…
|
aku
|
2475 |
} |
|
b058c8a…
|
mistachkin
|
2476 |
}else{ |
|
b058c8a…
|
mistachkin
|
2477 |
wasInit = 1; |
|
b058c8a…
|
mistachkin
|
2478 |
} |
|
b058c8a…
|
mistachkin
|
2479 |
if( forceSetup || !wasInit ){ |
|
b058c8a…
|
mistachkin
|
2480 |
int rc = TH_OK; |
|
b058c8a…
|
mistachkin
|
2481 |
if( !g.th1Setup ){ |
|
b058c8a…
|
mistachkin
|
2482 |
g.th1Setup = db_get("th1-setup", 0); /* Grab TH1 setup script. */ |
|
b058c8a…
|
mistachkin
|
2483 |
} |
|
b058c8a…
|
mistachkin
|
2484 |
if( g.th1Setup ){ |
|
b058c8a…
|
mistachkin
|
2485 |
rc = Th_Eval(g.interp, 0, g.th1Setup, -1); |
|
b058c8a…
|
mistachkin
|
2486 |
if( rc==TH_ERROR ){ |
|
b058c8a…
|
mistachkin
|
2487 |
int nResult = 0; |
|
b058c8a…
|
mistachkin
|
2488 |
char *zResult = (char*)Th_GetResult(g.interp, &nResult); |
|
5173701…
|
stephan
|
2489 |
sendError(0,zResult, nResult, 0); |
|
b058c8a…
|
mistachkin
|
2490 |
} |
|
b058c8a…
|
mistachkin
|
2491 |
} |
|
b058c8a…
|
mistachkin
|
2492 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
2493 |
Th_Trace("th1-setup {%h} => %h<br>\n", g.th1Setup, |
|
6c47a16…
|
mistachkin
|
2494 |
Th_ReturnCodeName(rc, 0)); |
|
6c47a16…
|
mistachkin
|
2495 |
} |
|
142200b…
|
mistachkin
|
2496 |
} |
|
142200b…
|
mistachkin
|
2497 |
g.th1Flags &= ~TH_INIT_MASK; |
|
142200b…
|
mistachkin
|
2498 |
g.th1Flags |= (flags & TH_INIT_MASK); |
|
8a65cd1…
|
mistachkin
|
2499 |
} |
|
8a65cd1…
|
mistachkin
|
2500 |
|
|
8a65cd1…
|
mistachkin
|
2501 |
/* |
|
8a65cd1…
|
mistachkin
|
2502 |
** Store a string value in a variable in the interpreter if the variable |
|
8a65cd1…
|
mistachkin
|
2503 |
** does not already exist. |
|
8a65cd1…
|
mistachkin
|
2504 |
*/ |
|
8a65cd1…
|
mistachkin
|
2505 |
void Th_MaybeStore(const char *zName, const char *zValue){ |
|
8a65cd1…
|
mistachkin
|
2506 |
Th_FossilInit(TH_INIT_DEFAULT); |
|
8a65cd1…
|
mistachkin
|
2507 |
if( zValue && !Th_ExistsVar(g.interp, zName, -1) ){ |
|
8a65cd1…
|
mistachkin
|
2508 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
2509 |
Th_Trace("maybe_set %h {%h}<br>\n", zName, zValue); |
|
8a65cd1…
|
mistachkin
|
2510 |
} |
|
8a65cd1…
|
mistachkin
|
2511 |
Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue)); |
|
8a65cd1…
|
mistachkin
|
2512 |
} |
|
588bb7c…
|
aku
|
2513 |
} |
|
588bb7c…
|
aku
|
2514 |
|
|
588bb7c…
|
aku
|
2515 |
/* |
|
588bb7c…
|
aku
|
2516 |
** Store a string value in a variable in the interpreter. |
|
588bb7c…
|
aku
|
2517 |
*/ |
|
588bb7c…
|
aku
|
2518 |
void Th_Store(const char *zName, const char *zValue){ |
|
0e68620…
|
mistachkin
|
2519 |
Th_FossilInit(TH_INIT_DEFAULT); |
|
f55c6a1…
|
drh
|
2520 |
if( zValue ){ |
|
f55c6a1…
|
drh
|
2521 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
2522 |
Th_Trace("set %h {%h}<br>\n", zName, zValue); |
|
f55c6a1…
|
drh
|
2523 |
} |
|
f55c6a1…
|
drh
|
2524 |
Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue)); |
|
2116238…
|
drh
|
2525 |
} |
|
2116238…
|
drh
|
2526 |
} |
|
2116238…
|
drh
|
2527 |
|
|
2116238…
|
drh
|
2528 |
/* |
|
2116238…
|
drh
|
2529 |
** Store a string value in a variable in the interpreter |
|
2116238…
|
drh
|
2530 |
** with the "taint" marking, so that TH1 knows that this |
|
2116238…
|
drh
|
2531 |
** variable contains content under the control of the remote |
|
2116238…
|
drh
|
2532 |
** user and presents a risk of XSS or SQL-injection attacks. |
|
2116238…
|
drh
|
2533 |
*/ |
|
2116238…
|
drh
|
2534 |
void Th_StoreUnsafe(const char *zName, const char *zValue){ |
|
2116238…
|
drh
|
2535 |
Th_FossilInit(TH_INIT_DEFAULT); |
|
2116238…
|
drh
|
2536 |
if( zValue ){ |
|
2116238…
|
drh
|
2537 |
if( g.thTrace ){ |
|
2116238…
|
drh
|
2538 |
Th_Trace("set %h [taint {%h}]<br>\n", zName, zValue); |
|
2116238…
|
drh
|
2539 |
} |
|
2116238…
|
drh
|
2540 |
Th_SetVar(g.interp, zName, -1, zValue, TH1_ADD_TAINT(strlen(zValue))); |
|
fc32fae…
|
mistachkin
|
2541 |
} |
|
fc32fae…
|
mistachkin
|
2542 |
} |
|
fc32fae…
|
mistachkin
|
2543 |
|
|
fc32fae…
|
mistachkin
|
2544 |
/* |
|
fc32fae…
|
mistachkin
|
2545 |
** Appends an element to a TH1 list value. This function is called by the |
|
fc32fae…
|
mistachkin
|
2546 |
** transfer subsystem; therefore, it must be very careful to avoid doing |
|
fc32fae…
|
mistachkin
|
2547 |
** any unnecessary work. To that end, the TH1 subsystem will not be called |
|
fc32fae…
|
mistachkin
|
2548 |
** or initialized if the list pointer is zero (i.e. which will be the case |
|
fc32fae…
|
mistachkin
|
2549 |
** when TH1 transfer hooks are disabled). |
|
fc32fae…
|
mistachkin
|
2550 |
*/ |
|
fc32fae…
|
mistachkin
|
2551 |
void Th_AppendToList( |
|
fc32fae…
|
mistachkin
|
2552 |
char **pzList, |
|
fc32fae…
|
mistachkin
|
2553 |
int *pnList, |
|
fc32fae…
|
mistachkin
|
2554 |
const char *zElem, |
|
fc32fae…
|
mistachkin
|
2555 |
int nElem |
|
fc32fae…
|
mistachkin
|
2556 |
){ |
|
fc32fae…
|
mistachkin
|
2557 |
if( pzList && zElem ){ |
|
fc32fae…
|
mistachkin
|
2558 |
Th_FossilInit(TH_INIT_DEFAULT); |
|
fc32fae…
|
mistachkin
|
2559 |
Th_ListAppend(g.interp, pzList, pnList, zElem, nElem); |
|
fc32fae…
|
mistachkin
|
2560 |
} |
|
fc32fae…
|
mistachkin
|
2561 |
} |
|
fc32fae…
|
mistachkin
|
2562 |
|
|
fc32fae…
|
mistachkin
|
2563 |
/* |
|
fc32fae…
|
mistachkin
|
2564 |
** Stores a list value in the specified TH1 variable using the specified |
|
fc32fae…
|
mistachkin
|
2565 |
** array of strings as the source of the element values. |
|
1c528d3…
|
mistachkin
|
2566 |
*/ |
|
1c528d3…
|
mistachkin
|
2567 |
void Th_StoreList( |
|
1c528d3…
|
mistachkin
|
2568 |
const char *zName, |
|
1c528d3…
|
mistachkin
|
2569 |
char **pzList, |
|
1c528d3…
|
mistachkin
|
2570 |
int nList |
|
1c528d3…
|
mistachkin
|
2571 |
){ |
|
1c528d3…
|
mistachkin
|
2572 |
Th_FossilInit(TH_INIT_DEFAULT); |
|
1c528d3…
|
mistachkin
|
2573 |
if( pzList ){ |
|
1c528d3…
|
mistachkin
|
2574 |
char *zValue = 0; |
|
1c528d3…
|
mistachkin
|
2575 |
int nValue = 0; |
|
1c528d3…
|
mistachkin
|
2576 |
int i; |
|
1c528d3…
|
mistachkin
|
2577 |
for(i=0; i<nList; i++){ |
|
1c528d3…
|
mistachkin
|
2578 |
Th_ListAppend(g.interp, &zValue, &nValue, pzList[i], -1); |
|
1c528d3…
|
mistachkin
|
2579 |
} |
|
1c528d3…
|
mistachkin
|
2580 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
2581 |
Th_Trace("set %h {%h}<br>\n", zName, zValue); |
|
1c528d3…
|
mistachkin
|
2582 |
} |
|
1c528d3…
|
mistachkin
|
2583 |
Th_SetVar(g.interp, zName, -1, zValue, nValue); |
|
1c528d3…
|
mistachkin
|
2584 |
Th_Free(g.interp, zValue); |
|
b058c8a…
|
mistachkin
|
2585 |
} |
|
b058c8a…
|
mistachkin
|
2586 |
} |
|
b058c8a…
|
mistachkin
|
2587 |
|
|
b058c8a…
|
mistachkin
|
2588 |
/* |
|
b058c8a…
|
mistachkin
|
2589 |
** Store an integer value in a variable in the interpreter. |
|
b058c8a…
|
mistachkin
|
2590 |
*/ |
|
b058c8a…
|
mistachkin
|
2591 |
void Th_StoreInt(const char *zName, int iValue){ |
|
b058c8a…
|
mistachkin
|
2592 |
Blob value; |
|
b058c8a…
|
mistachkin
|
2593 |
char *zValue; |
|
0e68620…
|
mistachkin
|
2594 |
Th_FossilInit(TH_INIT_DEFAULT); |
|
b058c8a…
|
mistachkin
|
2595 |
blob_zero(&value); |
|
b058c8a…
|
mistachkin
|
2596 |
blob_appendf(&value, "%d", iValue); |
|
b058c8a…
|
mistachkin
|
2597 |
zValue = blob_str(&value); |
|
b058c8a…
|
mistachkin
|
2598 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
2599 |
Th_Trace("set %h {%h}<br>\n", zName, zValue); |
|
b058c8a…
|
mistachkin
|
2600 |
} |
|
b058c8a…
|
mistachkin
|
2601 |
Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue)); |
|
b058c8a…
|
mistachkin
|
2602 |
blob_reset(&value); |
|
68c24b1…
|
drh
|
2603 |
} |
|
68c24b1…
|
drh
|
2604 |
|
|
68c24b1…
|
drh
|
2605 |
/* |
|
68c24b1…
|
drh
|
2606 |
** Unset a variable. |
|
68c24b1…
|
drh
|
2607 |
*/ |
|
68c24b1…
|
drh
|
2608 |
void Th_Unstore(const char *zName){ |
|
68c24b1…
|
drh
|
2609 |
if( g.interp ){ |
|
0c99a15…
|
drh
|
2610 |
Th_UnsetVar(g.interp, (char*)zName, -1); |
|
68c24b1…
|
drh
|
2611 |
} |
|
588bb7c…
|
aku
|
2612 |
} |
|
588bb7c…
|
aku
|
2613 |
|
|
588bb7c…
|
aku
|
2614 |
/* |
|
588bb7c…
|
aku
|
2615 |
** Retrieve a string value from the interpreter. If no such |
|
588bb7c…
|
aku
|
2616 |
** variable exists, return NULL. |
|
588bb7c…
|
aku
|
2617 |
*/ |
|
588bb7c…
|
aku
|
2618 |
char *Th_Fetch(const char *zName, int *pSize){ |
|
588bb7c…
|
aku
|
2619 |
int rc; |
|
0e68620…
|
mistachkin
|
2620 |
Th_FossilInit(TH_INIT_DEFAULT); |
|
0c99a15…
|
drh
|
2621 |
rc = Th_GetVar(g.interp, (char*)zName, -1); |
|
588bb7c…
|
aku
|
2622 |
if( rc==TH_OK ){ |
|
588bb7c…
|
aku
|
2623 |
return (char*)Th_GetResult(g.interp, pSize); |
|
588bb7c…
|
aku
|
2624 |
}else{ |
|
588bb7c…
|
aku
|
2625 |
return 0; |
|
588bb7c…
|
aku
|
2626 |
} |
|
588bb7c…
|
aku
|
2627 |
} |
|
588bb7c…
|
aku
|
2628 |
|
|
588bb7c…
|
aku
|
2629 |
/* |
|
588bb7c…
|
aku
|
2630 |
** Return true if the string begins with the TH1 begin-script |
|
588bb7c…
|
aku
|
2631 |
** tag: <th1>. |
|
588bb7c…
|
aku
|
2632 |
*/ |
|
588bb7c…
|
aku
|
2633 |
static int isBeginScriptTag(const char *z){ |
|
588bb7c…
|
aku
|
2634 |
return z[0]=='<' |
|
588bb7c…
|
aku
|
2635 |
&& (z[1]=='t' || z[1]=='T') |
|
588bb7c…
|
aku
|
2636 |
&& (z[2]=='h' || z[2]=='H') |
|
588bb7c…
|
aku
|
2637 |
&& z[3]=='1' |
|
588bb7c…
|
aku
|
2638 |
&& z[4]=='>'; |
|
588bb7c…
|
aku
|
2639 |
} |
|
588bb7c…
|
aku
|
2640 |
|
|
588bb7c…
|
aku
|
2641 |
/* |
|
588bb7c…
|
aku
|
2642 |
** Return true if the string begins with the TH1 end-script |
|
588bb7c…
|
aku
|
2643 |
** tag: </th1>. |
|
588bb7c…
|
aku
|
2644 |
*/ |
|
588bb7c…
|
aku
|
2645 |
static int isEndScriptTag(const char *z){ |
|
588bb7c…
|
aku
|
2646 |
return z[0]=='<' |
|
588bb7c…
|
aku
|
2647 |
&& z[1]=='/' |
|
588bb7c…
|
aku
|
2648 |
&& (z[2]=='t' || z[2]=='T') |
|
588bb7c…
|
aku
|
2649 |
&& (z[3]=='h' || z[3]=='H') |
|
588bb7c…
|
aku
|
2650 |
&& z[4]=='1' |
|
588bb7c…
|
aku
|
2651 |
&& z[5]=='>'; |
|
588bb7c…
|
aku
|
2652 |
} |
|
588bb7c…
|
aku
|
2653 |
|
|
588bb7c…
|
aku
|
2654 |
/* |
|
588bb7c…
|
aku
|
2655 |
** If string z[0...] contains a valid variable name, return |
|
588bb7c…
|
aku
|
2656 |
** the number of characters in that name. Otherwise, return 0. |
|
588bb7c…
|
aku
|
2657 |
*/ |
|
588bb7c…
|
aku
|
2658 |
static int validVarName(const char *z){ |
|
588bb7c…
|
aku
|
2659 |
int i = 0; |
|
588bb7c…
|
aku
|
2660 |
int inBracket = 0; |
|
588bb7c…
|
aku
|
2661 |
if( z[0]=='<' ){ |
|
588bb7c…
|
aku
|
2662 |
inBracket = 1; |
|
588bb7c…
|
aku
|
2663 |
z++; |
|
588bb7c…
|
aku
|
2664 |
} |
|
2fac809…
|
drh
|
2665 |
if( z[0]==':' && z[1]==':' && fossil_isalpha(z[2]) ){ |
|
588bb7c…
|
aku
|
2666 |
z += 3; |
|
588bb7c…
|
aku
|
2667 |
i += 3; |
|
2fac809…
|
drh
|
2668 |
}else if( fossil_isalpha(z[0]) ){ |
|
588bb7c…
|
aku
|
2669 |
z ++; |
|
588bb7c…
|
aku
|
2670 |
i += 1; |
|
588bb7c…
|
aku
|
2671 |
}else{ |
|
588bb7c…
|
aku
|
2672 |
return 0; |
|
588bb7c…
|
aku
|
2673 |
} |
|
2fac809…
|
drh
|
2674 |
while( fossil_isalnum(z[0]) || z[0]=='_' ){ |
|
588bb7c…
|
aku
|
2675 |
z++; |
|
588bb7c…
|
aku
|
2676 |
i++; |
|
588bb7c…
|
aku
|
2677 |
} |
|
588bb7c…
|
aku
|
2678 |
if( inBracket ){ |
|
588bb7c…
|
aku
|
2679 |
if( z[0]!='>' ) return 0; |
|
588bb7c…
|
aku
|
2680 |
i += 2; |
|
588bb7c…
|
aku
|
2681 |
} |
|
588bb7c…
|
aku
|
2682 |
return i; |
|
588bb7c…
|
aku
|
2683 |
} |
|
588bb7c…
|
aku
|
2684 |
|
|
1c528d3…
|
mistachkin
|
2685 |
#ifdef FOSSIL_ENABLE_TH1_HOOKS |
|
1c528d3…
|
mistachkin
|
2686 |
/* |
|
e52682e…
|
mistachkin
|
2687 |
** This function determines if TH1 hooks are enabled for the repository. It |
|
e52682e…
|
mistachkin
|
2688 |
** may be necessary to open the repository and/or the configuration ("user") |
|
e52682e…
|
mistachkin
|
2689 |
** database from within this function. Before this function returns, any |
|
e52682e…
|
mistachkin
|
2690 |
** database opened will be closed again. This is very important because some |
|
e52682e…
|
mistachkin
|
2691 |
** commands do not expect the repository and/or the configuration ("user") |
|
e52682e…
|
mistachkin
|
2692 |
** database to be open prior to their own code doing so. |
|
e52682e…
|
mistachkin
|
2693 |
*/ |
|
e52682e…
|
mistachkin
|
2694 |
int Th_AreHooksEnabled(void){ |
|
e52682e…
|
mistachkin
|
2695 |
int rc; |
|
e52682e…
|
mistachkin
|
2696 |
if( fossil_getenv("TH1_ENABLE_HOOKS")!=0 ){ |
|
e52682e…
|
mistachkin
|
2697 |
return 1; |
|
e52682e…
|
mistachkin
|
2698 |
} |
|
e52682e…
|
mistachkin
|
2699 |
Th_OpenConfig(1); |
|
e52682e…
|
mistachkin
|
2700 |
rc = db_get_boolean("th1-hooks", 0); |
|
e52682e…
|
mistachkin
|
2701 |
Th_CloseConfig(1); |
|
e52682e…
|
mistachkin
|
2702 |
return rc; |
|
e52682e…
|
mistachkin
|
2703 |
} |
|
e52682e…
|
mistachkin
|
2704 |
|
|
e52682e…
|
mistachkin
|
2705 |
/* |
|
1c528d3…
|
mistachkin
|
2706 |
** This function is called by Fossil just prior to dispatching a command. |
|
1c528d3…
|
mistachkin
|
2707 |
** Returning a value other than TH_OK from this function (i.e. via an |
|
1c528d3…
|
mistachkin
|
2708 |
** evaluated script raising an error or calling [break]/[continue]) will |
|
1c528d3…
|
mistachkin
|
2709 |
** cause the actual command execution to be skipped. |
|
1c528d3…
|
mistachkin
|
2710 |
*/ |
|
1c528d3…
|
mistachkin
|
2711 |
int Th_CommandHook( |
|
1c528d3…
|
mistachkin
|
2712 |
const char *zName, |
|
e6aab1a…
|
drh
|
2713 |
unsigned int cmdFlags |
|
1c528d3…
|
mistachkin
|
2714 |
){ |
|
1c528d3…
|
mistachkin
|
2715 |
int rc = TH_OK; |
|
e52682e…
|
mistachkin
|
2716 |
if( !Th_AreHooksEnabled() ) return rc; |
|
1c528d3…
|
mistachkin
|
2717 |
Th_FossilInit(TH_INIT_HOOK); |
|
1c528d3…
|
mistachkin
|
2718 |
Th_Store("cmd_name", zName); |
|
1c528d3…
|
mistachkin
|
2719 |
Th_StoreList("cmd_args", g.argv, g.argc); |
|
1c528d3…
|
mistachkin
|
2720 |
Th_StoreInt("cmd_flags", cmdFlags); |
|
1c528d3…
|
mistachkin
|
2721 |
rc = Th_Eval(g.interp, 0, "command_hook", -1); |
|
1c528d3…
|
mistachkin
|
2722 |
if( rc==TH_ERROR ){ |
|
1c528d3…
|
mistachkin
|
2723 |
int nResult = 0; |
|
1c528d3…
|
mistachkin
|
2724 |
char *zResult = (char*)Th_GetResult(g.interp, &nResult); |
|
1c528d3…
|
mistachkin
|
2725 |
/* |
|
1c528d3…
|
mistachkin
|
2726 |
** Make sure that the TH1 script error was not caused by a "missing" |
|
1c528d3…
|
mistachkin
|
2727 |
** command hook handler as that is not actually an error condition. |
|
1c528d3…
|
mistachkin
|
2728 |
*/ |
|
2116238…
|
drh
|
2729 |
nResult = TH1_LEN(nResult); |
|
1c528d3…
|
mistachkin
|
2730 |
if( memcmp(zResult, NO_COMMAND_HOOK_ERROR, nResult)!=0 ){ |
|
5173701…
|
stephan
|
2731 |
sendError(0,zResult, nResult, 0); |
|
a313f03…
|
mistachkin
|
2732 |
}else{ |
|
a313f03…
|
mistachkin
|
2733 |
/* |
|
a313f03…
|
mistachkin
|
2734 |
** There is no command hook handler "installed". This situation |
|
a313f03…
|
mistachkin
|
2735 |
** is NOT actually an error. |
|
a313f03…
|
mistachkin
|
2736 |
*/ |
|
a313f03…
|
mistachkin
|
2737 |
rc = TH_OK; |
|
1c528d3…
|
mistachkin
|
2738 |
} |
|
1c528d3…
|
mistachkin
|
2739 |
} |
|
1c528d3…
|
mistachkin
|
2740 |
/* |
|
1c528d3…
|
mistachkin
|
2741 |
** If the script returned TH_ERROR (e.g. the "command_hook" TH1 command does |
|
1c528d3…
|
mistachkin
|
2742 |
** not exist because commands are not being hooked), return TH_OK because we |
|
1c528d3…
|
mistachkin
|
2743 |
** do not want to skip executing essential commands unless the called command |
|
1c528d3…
|
mistachkin
|
2744 |
** (i.e. "command_hook") explicitly forbids this by successfully returning |
|
1c528d3…
|
mistachkin
|
2745 |
** TH_BREAK or TH_CONTINUE. |
|
1c528d3…
|
mistachkin
|
2746 |
*/ |
|
1c528d3…
|
mistachkin
|
2747 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
2748 |
Th_Trace("[command_hook {%h}] => %h<br>\n", zName, |
|
1c528d3…
|
mistachkin
|
2749 |
Th_ReturnCodeName(rc, 0)); |
|
1c528d3…
|
mistachkin
|
2750 |
} |
|
e52682e…
|
mistachkin
|
2751 |
/* |
|
e52682e…
|
mistachkin
|
2752 |
** Does our call to Th_FossilInit() result in opening a database? If so, |
|
e52682e…
|
mistachkin
|
2753 |
** clean it up now. This is very important because some commands do not |
|
e52682e…
|
mistachkin
|
2754 |
** expect the repository and/or the configuration ("user") database to be |
|
e52682e…
|
mistachkin
|
2755 |
** open prior to their own code doing so. |
|
e52682e…
|
mistachkin
|
2756 |
*/ |
|
e52682e…
|
mistachkin
|
2757 |
if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
|
a313f03…
|
mistachkin
|
2758 |
return rc; |
|
1c528d3…
|
mistachkin
|
2759 |
} |
|
1c528d3…
|
mistachkin
|
2760 |
|
|
1c528d3…
|
mistachkin
|
2761 |
/* |
|
1c528d3…
|
mistachkin
|
2762 |
** This function is called by Fossil just after dispatching a command. |
|
1c528d3…
|
mistachkin
|
2763 |
** Returning a value other than TH_OK from this function (i.e. via an |
|
1c528d3…
|
mistachkin
|
2764 |
** evaluated script raising an error or calling [break]/[continue]) may |
|
1c528d3…
|
mistachkin
|
2765 |
** cause an error message to be displayed to the local interactive user. |
|
1c528d3…
|
mistachkin
|
2766 |
** Currently, TH1 error messages generated by this function are ignored. |
|
1c528d3…
|
mistachkin
|
2767 |
*/ |
|
1c528d3…
|
mistachkin
|
2768 |
int Th_CommandNotify( |
|
1c528d3…
|
mistachkin
|
2769 |
const char *zName, |
|
e6aab1a…
|
drh
|
2770 |
unsigned int cmdFlags |
|
1c528d3…
|
mistachkin
|
2771 |
){ |
|
1c528d3…
|
mistachkin
|
2772 |
int rc = TH_OK; |
|
e52682e…
|
mistachkin
|
2773 |
if( !Th_AreHooksEnabled() ) return rc; |
|
1c528d3…
|
mistachkin
|
2774 |
Th_FossilInit(TH_INIT_HOOK); |
|
1c528d3…
|
mistachkin
|
2775 |
Th_Store("cmd_name", zName); |
|
1c528d3…
|
mistachkin
|
2776 |
Th_StoreList("cmd_args", g.argv, g.argc); |
|
1c528d3…
|
mistachkin
|
2777 |
Th_StoreInt("cmd_flags", cmdFlags); |
|
1c528d3…
|
mistachkin
|
2778 |
rc = Th_Eval(g.interp, 0, "command_notify", -1); |
|
1c528d3…
|
mistachkin
|
2779 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
2780 |
Th_Trace("[command_notify {%h}] => %h<br>\n", zName, |
|
1c528d3…
|
mistachkin
|
2781 |
Th_ReturnCodeName(rc, 0)); |
|
1c528d3…
|
mistachkin
|
2782 |
} |
|
e52682e…
|
mistachkin
|
2783 |
/* |
|
e52682e…
|
mistachkin
|
2784 |
** Does our call to Th_FossilInit() result in opening a database? If so, |
|
e52682e…
|
mistachkin
|
2785 |
** clean it up now. This is very important because some commands do not |
|
e52682e…
|
mistachkin
|
2786 |
** expect the repository and/or the configuration ("user") database to be |
|
e52682e…
|
mistachkin
|
2787 |
** open prior to their own code doing so. |
|
e52682e…
|
mistachkin
|
2788 |
*/ |
|
e52682e…
|
mistachkin
|
2789 |
if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
|
1c528d3…
|
mistachkin
|
2790 |
return rc; |
|
1c528d3…
|
mistachkin
|
2791 |
} |
|
1c528d3…
|
mistachkin
|
2792 |
|
|
1c528d3…
|
mistachkin
|
2793 |
/* |
|
1c528d3…
|
mistachkin
|
2794 |
** This function is called by Fossil just prior to processing a web page. |
|
1c528d3…
|
mistachkin
|
2795 |
** Returning a value other than TH_OK from this function (i.e. via an |
|
1c528d3…
|
mistachkin
|
2796 |
** evaluated script raising an error or calling [break]/[continue]) will |
|
1c528d3…
|
mistachkin
|
2797 |
** cause the actual web page processing to be skipped. |
|
1c528d3…
|
mistachkin
|
2798 |
*/ |
|
1c528d3…
|
mistachkin
|
2799 |
int Th_WebpageHook( |
|
1c528d3…
|
mistachkin
|
2800 |
const char *zName, |
|
3ca2bc1…
|
mistachkin
|
2801 |
unsigned int cmdFlags |
|
1c528d3…
|
mistachkin
|
2802 |
){ |
|
1c528d3…
|
mistachkin
|
2803 |
int rc = TH_OK; |
|
e52682e…
|
mistachkin
|
2804 |
if( !Th_AreHooksEnabled() ) return rc; |
|
1c528d3…
|
mistachkin
|
2805 |
Th_FossilInit(TH_INIT_HOOK); |
|
1c528d3…
|
mistachkin
|
2806 |
Th_Store("web_name", zName); |
|
1c528d3…
|
mistachkin
|
2807 |
Th_StoreList("web_args", g.argv, g.argc); |
|
1c528d3…
|
mistachkin
|
2808 |
Th_StoreInt("web_flags", cmdFlags); |
|
1c528d3…
|
mistachkin
|
2809 |
rc = Th_Eval(g.interp, 0, "webpage_hook", -1); |
|
1c528d3…
|
mistachkin
|
2810 |
if( rc==TH_ERROR ){ |
|
1c528d3…
|
mistachkin
|
2811 |
int nResult = 0; |
|
1c528d3…
|
mistachkin
|
2812 |
char *zResult = (char*)Th_GetResult(g.interp, &nResult); |
|
1c528d3…
|
mistachkin
|
2813 |
/* |
|
1c528d3…
|
mistachkin
|
2814 |
** Make sure that the TH1 script error was not caused by a "missing" |
|
1c528d3…
|
mistachkin
|
2815 |
** webpage hook handler as that is not actually an error condition. |
|
1c528d3…
|
mistachkin
|
2816 |
*/ |
|
2116238…
|
drh
|
2817 |
nResult = TH1_LEN(nResult); |
|
1c528d3…
|
mistachkin
|
2818 |
if( memcmp(zResult, NO_WEBPAGE_HOOK_ERROR, nResult)!=0 ){ |
|
5173701…
|
stephan
|
2819 |
sendError(0,zResult, nResult, 1); |
|
a313f03…
|
mistachkin
|
2820 |
}else{ |
|
a313f03…
|
mistachkin
|
2821 |
/* |
|
a313f03…
|
mistachkin
|
2822 |
** There is no webpage hook handler "installed". This situation |
|
a313f03…
|
mistachkin
|
2823 |
** is NOT actually an error. |
|
a313f03…
|
mistachkin
|
2824 |
*/ |
|
a313f03…
|
mistachkin
|
2825 |
rc = TH_OK; |
|
1c528d3…
|
mistachkin
|
2826 |
} |
|
1c528d3…
|
mistachkin
|
2827 |
} |
|
1c528d3…
|
mistachkin
|
2828 |
/* |
|
1c528d3…
|
mistachkin
|
2829 |
** If the script returned TH_ERROR (e.g. the "webpage_hook" TH1 command does |
|
1c528d3…
|
mistachkin
|
2830 |
** not exist because commands are not being hooked), return TH_OK because we |
|
1c528d3…
|
mistachkin
|
2831 |
** do not want to skip processing essential web pages unless the called |
|
1c528d3…
|
mistachkin
|
2832 |
** command (i.e. "webpage_hook") explicitly forbids this by successfully |
|
1c528d3…
|
mistachkin
|
2833 |
** returning TH_BREAK or TH_CONTINUE. |
|
1c528d3…
|
mistachkin
|
2834 |
*/ |
|
1c528d3…
|
mistachkin
|
2835 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
2836 |
Th_Trace("[webpage_hook {%h}] => %h<br>\n", zName, |
|
1c528d3…
|
mistachkin
|
2837 |
Th_ReturnCodeName(rc, 0)); |
|
1c528d3…
|
mistachkin
|
2838 |
} |
|
e52682e…
|
mistachkin
|
2839 |
/* |
|
e52682e…
|
mistachkin
|
2840 |
** Does our call to Th_FossilInit() result in opening a database? If so, |
|
e52682e…
|
mistachkin
|
2841 |
** clean it up now. This is very important because some commands do not |
|
e52682e…
|
mistachkin
|
2842 |
** expect the repository and/or the configuration ("user") database to be |
|
e52682e…
|
mistachkin
|
2843 |
** open prior to their own code doing so. |
|
e52682e…
|
mistachkin
|
2844 |
*/ |
|
e52682e…
|
mistachkin
|
2845 |
if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
|
a313f03…
|
mistachkin
|
2846 |
return rc; |
|
1c528d3…
|
mistachkin
|
2847 |
} |
|
1c528d3…
|
mistachkin
|
2848 |
|
|
1c528d3…
|
mistachkin
|
2849 |
/* |
|
1c528d3…
|
mistachkin
|
2850 |
** This function is called by Fossil just after processing a web page. |
|
1c528d3…
|
mistachkin
|
2851 |
** Returning a value other than TH_OK from this function (i.e. via an |
|
1c528d3…
|
mistachkin
|
2852 |
** evaluated script raising an error or calling [break]/[continue]) may |
|
1c528d3…
|
mistachkin
|
2853 |
** cause an error message to be displayed to the remote user. |
|
1c528d3…
|
mistachkin
|
2854 |
** Currently, TH1 error messages generated by this function are ignored. |
|
1c528d3…
|
mistachkin
|
2855 |
*/ |
|
1c528d3…
|
mistachkin
|
2856 |
int Th_WebpageNotify( |
|
1c528d3…
|
mistachkin
|
2857 |
const char *zName, |
|
3ca2bc1…
|
mistachkin
|
2858 |
unsigned int cmdFlags |
|
1c528d3…
|
mistachkin
|
2859 |
){ |
|
1c528d3…
|
mistachkin
|
2860 |
int rc = TH_OK; |
|
e52682e…
|
mistachkin
|
2861 |
if( !Th_AreHooksEnabled() ) return rc; |
|
1c528d3…
|
mistachkin
|
2862 |
Th_FossilInit(TH_INIT_HOOK); |
|
1c528d3…
|
mistachkin
|
2863 |
Th_Store("web_name", zName); |
|
1c528d3…
|
mistachkin
|
2864 |
Th_StoreList("web_args", g.argv, g.argc); |
|
1c528d3…
|
mistachkin
|
2865 |
Th_StoreInt("web_flags", cmdFlags); |
|
1c528d3…
|
mistachkin
|
2866 |
rc = Th_Eval(g.interp, 0, "webpage_notify", -1); |
|
1c528d3…
|
mistachkin
|
2867 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
2868 |
Th_Trace("[webpage_notify {%h}] => %h<br>\n", zName, |
|
1c528d3…
|
mistachkin
|
2869 |
Th_ReturnCodeName(rc, 0)); |
|
1c528d3…
|
mistachkin
|
2870 |
} |
|
e52682e…
|
mistachkin
|
2871 |
/* |
|
e52682e…
|
mistachkin
|
2872 |
** Does our call to Th_FossilInit() result in opening a database? If so, |
|
e52682e…
|
mistachkin
|
2873 |
** clean it up now. This is very important because some commands do not |
|
e52682e…
|
mistachkin
|
2874 |
** expect the repository and/or the configuration ("user") database to be |
|
e52682e…
|
mistachkin
|
2875 |
** open prior to their own code doing so. |
|
e52682e…
|
mistachkin
|
2876 |
*/ |
|
e52682e…
|
mistachkin
|
2877 |
if( TH_INIT_HOOK & TH_INIT_NEED_CONFIG ) Th_CloseConfig(1); |
|
1c528d3…
|
mistachkin
|
2878 |
return rc; |
|
1c528d3…
|
mistachkin
|
2879 |
} |
|
1c528d3…
|
mistachkin
|
2880 |
#endif |
|
1c528d3…
|
mistachkin
|
2881 |
|
|
71536a2…
|
mistachkin
|
2882 |
|
|
71536a2…
|
mistachkin
|
2883 |
#ifdef FOSSIL_ENABLE_TH1_DOCS |
|
71536a2…
|
mistachkin
|
2884 |
/* |
|
71536a2…
|
mistachkin
|
2885 |
** This function determines if TH1 docs are enabled for the repository. |
|
71536a2…
|
mistachkin
|
2886 |
*/ |
|
71536a2…
|
mistachkin
|
2887 |
int Th_AreDocsEnabled(void){ |
|
71536a2…
|
mistachkin
|
2888 |
if( fossil_getenv("TH1_ENABLE_DOCS")!=0 ){ |
|
71536a2…
|
mistachkin
|
2889 |
return 1; |
|
71536a2…
|
mistachkin
|
2890 |
} |
|
71536a2…
|
mistachkin
|
2891 |
return db_get_boolean("th1-docs", 0); |
|
71536a2…
|
mistachkin
|
2892 |
} |
|
71536a2…
|
mistachkin
|
2893 |
#endif |
|
71536a2…
|
mistachkin
|
2894 |
|
|
71536a2…
|
mistachkin
|
2895 |
|
|
5173701…
|
stephan
|
2896 |
#if INTERFACE |
|
5173701…
|
stephan
|
2897 |
/* |
|
5173701…
|
stephan
|
2898 |
** Flags for use with Th_RenderToBlob. These must not overlap with |
|
5173701…
|
stephan
|
2899 |
** TH_INIT_MASK. |
|
5173701…
|
stephan
|
2900 |
*/ |
|
5173701…
|
stephan
|
2901 |
#define TH_R2B_MASK ((u32)0x0f000) |
|
5173701…
|
stephan
|
2902 |
#define TH_R2B_NO_VARS ((u32)0x01000) /* Disables eval of $vars and $<vars> */ |
|
5173701…
|
stephan
|
2903 |
#endif |
|
5173701…
|
stephan
|
2904 |
|
|
588bb7c…
|
aku
|
2905 |
/* |
|
a5f00e0…
|
stephan
|
2906 |
** If pOut is NULL, this works identically to Th_Render() and sends |
|
a5f00e0…
|
stephan
|
2907 |
** any TH1-generated output to stdin (in CLI mode) or the CGI buffer |
|
a5f00e0…
|
stephan
|
2908 |
** (in CGI mode), else it works just like that function but appends |
|
a5f00e0…
|
stephan
|
2909 |
** any TH1-generated output to the given blob. A bitmask of TH_R2B_xxx |
|
a5f00e0…
|
stephan
|
2910 |
** and/or TH_INIT_xxx flags may be passed as the 3rd argument, or 0 |
|
a5f00e0…
|
stephan
|
2911 |
** for default options. Note that this function necessarily calls |
|
a5f00e0…
|
stephan
|
2912 |
** Th_FossilInit(), which may unset flags used on previous calls |
|
a5f00e0…
|
stephan
|
2913 |
** unless mFlags is explicitly passed in. |
|
588bb7c…
|
aku
|
2914 |
*/ |
|
5173701…
|
stephan
|
2915 |
int Th_RenderToBlob(const char *z, Blob * pOut, u32 mFlags){ |
|
588bb7c…
|
aku
|
2916 |
int i = 0; |
|
588bb7c…
|
aku
|
2917 |
int n; |
|
588bb7c…
|
aku
|
2918 |
int rc = TH_OK; |
|
0c99a15…
|
drh
|
2919 |
char *zResult; |
|
5173701…
|
stephan
|
2920 |
Blob * const origOut = Th_SetOutputBlob(pOut); |
|
5173701…
|
stephan
|
2921 |
|
|
5173701…
|
stephan
|
2922 |
assert(0==(TH_R2B_MASK & TH_INIT_MASK) && "init/r2b mask conflict"); |
|
5173701…
|
stephan
|
2923 |
Th_FossilInit(mFlags & TH_INIT_MASK); |
|
588bb7c…
|
aku
|
2924 |
while( z[i] ){ |
|
5173701…
|
stephan
|
2925 |
if( 0==(TH_R2B_NO_VARS & mFlags) |
|
5173701…
|
stephan
|
2926 |
&& z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){ |
|
588bb7c…
|
aku
|
2927 |
const char *zVar; |
|
588bb7c…
|
aku
|
2928 |
int nVar; |
|
aeec10b…
|
drh
|
2929 |
int encode = 1; |
|
5173701…
|
stephan
|
2930 |
sendText(pOut,z, i, 0); |
|
588bb7c…
|
aku
|
2931 |
if( z[i+1]=='<' ){ |
|
aeec10b…
|
drh
|
2932 |
/* Variables of the form $<aaa> are html escaped */ |
|
588bb7c…
|
aku
|
2933 |
zVar = &z[i+2]; |
|
588bb7c…
|
aku
|
2934 |
nVar = n-2; |
|
588bb7c…
|
aku
|
2935 |
}else{ |
|
aeec10b…
|
drh
|
2936 |
/* Variables of the form $aaa are output raw */ |
|
588bb7c…
|
aku
|
2937 |
zVar = &z[i+1]; |
|
588bb7c…
|
aku
|
2938 |
nVar = n; |
|
aeec10b…
|
drh
|
2939 |
encode = 0; |
|
588bb7c…
|
aku
|
2940 |
} |
|
0c99a15…
|
drh
|
2941 |
rc = Th_GetVar(g.interp, (char*)zVar, nVar); |
|
588bb7c…
|
aku
|
2942 |
z += i+1+n; |
|
588bb7c…
|
aku
|
2943 |
i = 0; |
|
0c99a15…
|
drh
|
2944 |
zResult = (char*)Th_GetResult(g.interp, &n); |
|
d259be4…
|
drh
|
2945 |
if( !TH1_TAINTED(n) |
|
d259be4…
|
drh
|
2946 |
|| encode |
|
d259be4…
|
drh
|
2947 |
|| Th_ReportTaint(g.interp, "inline variable", zVar, nVar)==TH_OK |
|
d259be4…
|
drh
|
2948 |
){ |
|
d259be4…
|
drh
|
2949 |
sendText(pOut,(char*)zResult, n, encode); |
|
d259be4…
|
drh
|
2950 |
} |
|
588bb7c…
|
aku
|
2951 |
}else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){ |
|
5173701…
|
stephan
|
2952 |
sendText(pOut,z, i, 0); |
|
588bb7c…
|
aku
|
2953 |
z += i+5; |
|
588bb7c…
|
aku
|
2954 |
for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){} |
|
4f8c897…
|
drh
|
2955 |
if( g.thTrace ){ |
|
f5482a0…
|
wyoung
|
2956 |
Th_Trace("render_eval {<pre>%#h</pre>}<br>\n", i, z); |
|
4f8c897…
|
drh
|
2957 |
} |
|
0c99a15…
|
drh
|
2958 |
rc = Th_Eval(g.interp, 0, (const char*)z, i); |
|
fee9ede…
|
mistachkin
|
2959 |
if( g.thTrace ){ |
|
fee9ede…
|
mistachkin
|
2960 |
int nTrRes; |
|
fee9ede…
|
mistachkin
|
2961 |
char *zTrRes = (char*)Th_GetResult(g.interp, &nTrRes); |
|
f5482a0…
|
wyoung
|
2962 |
Th_Trace("[render_eval] => %h {%#h}<br>\n", |
|
2116238…
|
drh
|
2963 |
Th_ReturnCodeName(rc, 0), TH1_LEN(nTrRes), zTrRes); |
|
fee9ede…
|
mistachkin
|
2964 |
} |
|
588bb7c…
|
aku
|
2965 |
if( rc!=TH_OK ) break; |
|
588bb7c…
|
aku
|
2966 |
z += i; |
|
588bb7c…
|
aku
|
2967 |
if( z[0] ){ z += 6; } |
|
588bb7c…
|
aku
|
2968 |
i = 0; |
|
588bb7c…
|
aku
|
2969 |
}else{ |
|
b853b5d…
|
drh
|
2970 |
i += strcspn(&z[i+1], "<$") + 1; |
|
588bb7c…
|
aku
|
2971 |
} |
|
588bb7c…
|
aku
|
2972 |
} |
|
588bb7c…
|
aku
|
2973 |
if( rc==TH_ERROR ){ |
|
0c99a15…
|
drh
|
2974 |
zResult = (char*)Th_GetResult(g.interp, &n); |
|
5173701…
|
stephan
|
2975 |
sendError(pOut,zResult, n, 1); |
|
588bb7c…
|
aku
|
2976 |
}else{ |
|
5173701…
|
stephan
|
2977 |
sendText(pOut,z, i, 0); |
|
588bb7c…
|
aku
|
2978 |
} |
|
5173701…
|
stephan
|
2979 |
Th_SetOutputBlob(origOut); |
|
588bb7c…
|
aku
|
2980 |
return rc; |
|
5173701…
|
stephan
|
2981 |
} |
|
5173701…
|
stephan
|
2982 |
|
|
5173701…
|
stephan
|
2983 |
/* |
|
5173701…
|
stephan
|
2984 |
** The z[] input contains text mixed with TH1 scripts. |
|
5173701…
|
stephan
|
2985 |
** The TH1 scripts are contained within <th1>...</th1>. |
|
5173701…
|
stephan
|
2986 |
** TH1 variables are $aaa or $<aaa>. The first form of |
|
5173701…
|
stephan
|
2987 |
** variable is literal. The second is run through htmlize |
|
5173701…
|
stephan
|
2988 |
** before being inserted. |
|
5173701…
|
stephan
|
2989 |
** |
|
5173701…
|
stephan
|
2990 |
** This routine processes the template and writes the results to one |
|
5173701…
|
stephan
|
2991 |
** of stdout, CGI, or an internal blob which was set up via a prior |
|
5173701…
|
stephan
|
2992 |
** call to Th_SetOutputBlob(). |
|
5173701…
|
stephan
|
2993 |
*/ |
|
5173701…
|
stephan
|
2994 |
int Th_Render(const char *z){ |
|
a5f00e0…
|
stephan
|
2995 |
return Th_RenderToBlob(z, pThOut, g.th1Flags) |
|
a5f00e0…
|
stephan
|
2996 |
/* Maintenance reminder: on most calls to Th_Render(), e.g. for |
|
a5f00e0…
|
stephan
|
2997 |
** outputing the site skin, pThOut will be 0, which means that |
|
a5f00e0…
|
stephan
|
2998 |
** Th_RenderToBlob() will output directly to the CGI buffer (in |
|
a5f00e0…
|
stephan
|
2999 |
** CGI mode) or stdout (in CLI mode). Recursive calls, however, |
|
a5f00e0…
|
stephan
|
3000 |
** e.g. via the "render" script function binding, need to use the |
|
a5f00e0…
|
stephan
|
3001 |
** pThOut blob in order to avoid out-of-order output if |
|
a5f00e0…
|
stephan
|
3002 |
** Th_SetOutputBlob() has been called. If it has not been called, |
|
a5f00e0…
|
stephan
|
3003 |
** pThOut will be 0, which will redirect the output to CGI/stdout, |
|
a5f00e0…
|
stephan
|
3004 |
** as appropriate. We need to pass on g.th1Flags for the case of |
|
9164a5d…
|
drh
|
3005 |
** recursive calls. |
|
a5f00e0…
|
stephan
|
3006 |
*/; |
|
2116238…
|
drh
|
3007 |
} |
|
2116238…
|
drh
|
3008 |
|
|
2116238…
|
drh
|
3009 |
/* |
|
2116238…
|
drh
|
3010 |
** SETTING: vuln-report width=8 default=log |
|
2116238…
|
drh
|
3011 |
** |
|
2116238…
|
drh
|
3012 |
** This setting controls Fossil's behavior when it encounters a potential |
|
2116238…
|
drh
|
3013 |
** XSS or SQL-injection vulnerability due to misuse of TH1 configuration |
|
2116238…
|
drh
|
3014 |
** scripts. Choices are: |
|
2116238…
|
drh
|
3015 |
** |
|
2116238…
|
drh
|
3016 |
** off Do nothing. Ignore the vulnerability. |
|
2116238…
|
drh
|
3017 |
** |
|
2116238…
|
drh
|
3018 |
** log Write a report of the problem into the error log. |
|
2116238…
|
drh
|
3019 |
** |
|
2116238…
|
drh
|
3020 |
** block Like "log" but also prevent the offending TH1 command |
|
2116238…
|
drh
|
3021 |
** from running. |
|
2116238…
|
drh
|
3022 |
** |
|
2116238…
|
drh
|
3023 |
** fatal Render an error message page instead of the requested |
|
2116238…
|
drh
|
3024 |
** page. |
|
2116238…
|
drh
|
3025 |
*/ |
|
2116238…
|
drh
|
3026 |
|
|
2116238…
|
drh
|
3027 |
/* |
|
2116238…
|
drh
|
3028 |
** Report misuse of a tainted string in TH1. |
|
2116238…
|
drh
|
3029 |
** |
|
2116238…
|
drh
|
3030 |
** The behavior depends on the vuln-report setting. If "off", this routine |
|
2116238…
|
drh
|
3031 |
** is a no-op. Otherwise, right a message into the error log. If |
|
2116238…
|
drh
|
3032 |
** vuln-report is "log", that is all that happens. But for any other |
|
2116238…
|
drh
|
3033 |
** value of vuln-report, a fatal error is raised. |
|
2116238…
|
drh
|
3034 |
*/ |
|
2116238…
|
drh
|
3035 |
int Th_ReportTaint( |
|
2116238…
|
drh
|
3036 |
Th_Interp *interp, /* Report error here, if an error is reported */ |
|
2116238…
|
drh
|
3037 |
const char *zWhere, /* Where the tainted string appears */ |
|
2116238…
|
drh
|
3038 |
const char *zStr, /* The tainted string */ |
|
2116238…
|
drh
|
3039 |
int nStr /* Length of the tainted string */ |
|
2116238…
|
drh
|
3040 |
){ |
|
76f1ddb…
|
drh
|
3041 |
static const char *zDisp = 0; /* Dispensation; what to do with the error */ |
|
76f1ddb…
|
drh
|
3042 |
const char *zVulnType; /* Type of vulnerability */ |
|
2116238…
|
drh
|
3043 |
|
|
76f1ddb…
|
drh
|
3044 |
if( zDisp==0 ) zDisp = db_get("vuln-report","log"); |
|
2116238…
|
drh
|
3045 |
if( is_false(zDisp) ) return 0; |
|
2116238…
|
drh
|
3046 |
if( strstr(zWhere,"SQL")!=0 ){ |
|
2116238…
|
drh
|
3047 |
zVulnType = "SQL-injection"; |
|
2116238…
|
drh
|
3048 |
}else{ |
|
2116238…
|
drh
|
3049 |
zVulnType = "XSS"; |
|
2116238…
|
drh
|
3050 |
} |
|
2116238…
|
drh
|
3051 |
nStr = TH1_LEN(nStr); |
|
d259be4…
|
drh
|
3052 |
fossil_errorlog("possible TH1 %s vulnerability due to tainted %s: \"%.*s\"", |
|
2116238…
|
drh
|
3053 |
zVulnType, zWhere, nStr, zStr); |
|
2116238…
|
drh
|
3054 |
if( strcmp(zDisp,"log")==0 ){ |
|
2116238…
|
drh
|
3055 |
return 0; |
|
2116238…
|
drh
|
3056 |
} |
|
2116238…
|
drh
|
3057 |
if( strcmp(zDisp,"block")==0 ){ |
|
2116238…
|
drh
|
3058 |
char *z = mprintf("tainted %s: \"", zWhere); |
|
2116238…
|
drh
|
3059 |
Th_ErrorMessage(interp, z, zStr, nStr); |
|
2116238…
|
drh
|
3060 |
fossil_free(z); |
|
2116238…
|
drh
|
3061 |
}else{ |
|
2116238…
|
drh
|
3062 |
char *z = mprintf("%#h", nStr, zStr); |
|
76f1ddb…
|
drh
|
3063 |
zDisp = "off"; |
|
2116238…
|
drh
|
3064 |
cgi_reset_content(); |
|
2116238…
|
drh
|
3065 |
style_submenu_enable(0); |
|
2116238…
|
drh
|
3066 |
style_set_current_feature("error"); |
|
2116238…
|
drh
|
3067 |
style_header("Configuration Error"); |
|
2116238…
|
drh
|
3068 |
@ <p>Error in a TH1 configuration script: |
|
2116238…
|
drh
|
3069 |
@ tainted %h(zWhere): "%z(z)" |
|
2116238…
|
drh
|
3070 |
style_finish_page(); |
|
2116238…
|
drh
|
3071 |
cgi_reply(); |
|
2116238…
|
drh
|
3072 |
fossil_exit(1); |
|
2116238…
|
drh
|
3073 |
} |
|
2116238…
|
drh
|
3074 |
return 1; |
|
924315b…
|
drh
|
3075 |
} |
|
924315b…
|
drh
|
3076 |
|
|
924315b…
|
drh
|
3077 |
/* |
|
588bb7c…
|
aku
|
3078 |
** COMMAND: test-th-render |
|
924315b…
|
drh
|
3079 |
** |
|
924315b…
|
drh
|
3080 |
** Usage: %fossil test-th-render FILE |
|
924315b…
|
drh
|
3081 |
** |
|
924315b…
|
drh
|
3082 |
** Read the content of the file named "FILE" as if it were a header or |
|
924315b…
|
drh
|
3083 |
** footer or ticket rendering script, evaluate it, and show the results |
|
924315b…
|
drh
|
3084 |
** on standard output. |
|
924315b…
|
drh
|
3085 |
** |
|
924315b…
|
drh
|
3086 |
** Options: |
|
924315b…
|
drh
|
3087 |
** --cgi Include a CGI response header in the output |
|
924315b…
|
drh
|
3088 |
** --http Include an HTTP response header in the output |
|
924315b…
|
drh
|
3089 |
** --open-config Open the configuration database |
|
5ea2a4f…
|
mistachkin
|
3090 |
** --set-anon-caps Set anonymous login capabilities |
|
5ea2a4f…
|
mistachkin
|
3091 |
** --set-user-caps Set user login capabilities |
|
ddd4cb5…
|
mistachkin
|
3092 |
** --th-trace Trace TH1 execution (for debugging purposes) |
|
588bb7c…
|
aku
|
3093 |
*/ |
|
588bb7c…
|
aku
|
3094 |
void test_th_render(void){ |
|
f141fbe…
|
mistachkin
|
3095 |
int forceCgi, fullHttpReply; |
|
588bb7c…
|
aku
|
3096 |
Blob in; |
|
0264475…
|
mistachkin
|
3097 |
Th_InitTraceLog(); |
|
924315b…
|
drh
|
3098 |
forceCgi = find_option("cgi", 0, 0)!=0; |
|
924315b…
|
drh
|
3099 |
fullHttpReply = find_option("http", 0, 0)!=0; |
|
924315b…
|
drh
|
3100 |
if( fullHttpReply ) forceCgi = 1; |
|
c1915c3…
|
mistachkin
|
3101 |
if( forceCgi ) Th_ForceCgi(fullHttpReply); |
|
924315b…
|
drh
|
3102 |
if( find_option("open-config", 0, 0)!=0 ){ |
|
9773eba…
|
mistachkin
|
3103 |
Th_OpenConfig(1); |
|
9773eba…
|
mistachkin
|
3104 |
} |
|
5ea2a4f…
|
mistachkin
|
3105 |
if( find_option("set-anon-caps", 0, 0)!=0 ){ |
|
5915e6f…
|
mistachkin
|
3106 |
const char *zCap = fossil_getenv("TH1_TEST_ANON_CAPS"); |
|
5915e6f…
|
mistachkin
|
3107 |
login_set_capabilities(zCap ? zCap : "sx", LOGIN_ANON); |
|
5ea2a4f…
|
mistachkin
|
3108 |
g.useLocalauth = 1; |
|
5ea2a4f…
|
mistachkin
|
3109 |
} |
|
5ea2a4f…
|
mistachkin
|
3110 |
if( find_option("set-user-caps", 0, 0)!=0 ){ |
|
5915e6f…
|
mistachkin
|
3111 |
const char *zCap = fossil_getenv("TH1_TEST_USER_CAPS"); |
|
5915e6f…
|
mistachkin
|
3112 |
login_set_capabilities(zCap ? zCap : "sx", 0); |
|
5ea2a4f…
|
mistachkin
|
3113 |
g.useLocalauth = 1; |
|
5ea2a4f…
|
mistachkin
|
3114 |
} |
|
2116238…
|
drh
|
3115 |
db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0); |
|
924315b…
|
drh
|
3116 |
verify_all_options(); |
|
588bb7c…
|
aku
|
3117 |
if( g.argc<3 ){ |
|
588bb7c…
|
aku
|
3118 |
usage("FILE"); |
|
588bb7c…
|
aku
|
3119 |
} |
|
588bb7c…
|
aku
|
3120 |
blob_zero(&in); |
|
1772357…
|
drh
|
3121 |
blob_read_from_file(&in, g.argv[2], ExtFILE); |
|
588bb7c…
|
aku
|
3122 |
Th_Render(blob_str(&in)); |
|
0264475…
|
mistachkin
|
3123 |
Th_PrintTraceLog(); |
|
c1915c3…
|
mistachkin
|
3124 |
if( forceCgi ) cgi_reply(); |
|
6c47a16…
|
mistachkin
|
3125 |
} |
|
6c47a16…
|
mistachkin
|
3126 |
|
|
6c47a16…
|
mistachkin
|
3127 |
/* |
|
6c47a16…
|
mistachkin
|
3128 |
** COMMAND: test-th-eval |
|
924315b…
|
drh
|
3129 |
** |
|
924315b…
|
drh
|
3130 |
** Usage: %fossil test-th-eval SCRIPT |
|
924315b…
|
drh
|
3131 |
** |
|
924315b…
|
drh
|
3132 |
** Evaluate SCRIPT as if it were a header or footer or ticket rendering |
|
6456fab…
|
stephan
|
3133 |
** script and show the results on standard output. SCRIPT may be either |
|
6456fab…
|
stephan
|
3134 |
** a filename or a string of th1 script code. |
|
924315b…
|
drh
|
3135 |
** |
|
924315b…
|
drh
|
3136 |
** Options: |
|
924315b…
|
drh
|
3137 |
** --cgi Include a CGI response header in the output |
|
924315b…
|
drh
|
3138 |
** --http Include an HTTP response header in the output |
|
924315b…
|
drh
|
3139 |
** --open-config Open the configuration database |
|
5ea2a4f…
|
mistachkin
|
3140 |
** --set-anon-caps Set anonymous login capabilities |
|
5ea2a4f…
|
mistachkin
|
3141 |
** --set-user-caps Set user login capabilities |
|
ddd4cb5…
|
mistachkin
|
3142 |
** --th-trace Trace TH1 execution (for debugging purposes) |
|
6c47a16…
|
mistachkin
|
3143 |
*/ |
|
6c47a16…
|
mistachkin
|
3144 |
void test_th_eval(void){ |
|
6c47a16…
|
mistachkin
|
3145 |
int rc; |
|
6c47a16…
|
mistachkin
|
3146 |
const char *zRc; |
|
6456fab…
|
stephan
|
3147 |
const char *zCode = 0; |
|
c1915c3…
|
mistachkin
|
3148 |
int forceCgi, fullHttpReply; |
|
6456fab…
|
stephan
|
3149 |
Blob code = empty_blob; |
|
f141fbe…
|
mistachkin
|
3150 |
Th_InitTraceLog(); |
|
f141fbe…
|
mistachkin
|
3151 |
forceCgi = find_option("cgi", 0, 0)!=0; |
|
f141fbe…
|
mistachkin
|
3152 |
fullHttpReply = find_option("http", 0, 0)!=0; |
|
f141fbe…
|
mistachkin
|
3153 |
if( fullHttpReply ) forceCgi = 1; |
|
f141fbe…
|
mistachkin
|
3154 |
if( forceCgi ) Th_ForceCgi(fullHttpReply); |
|
f141fbe…
|
mistachkin
|
3155 |
if( find_option("open-config", 0, 0)!=0 ){ |
|
f141fbe…
|
mistachkin
|
3156 |
Th_OpenConfig(1); |
|
f141fbe…
|
mistachkin
|
3157 |
} |
|
5ea2a4f…
|
mistachkin
|
3158 |
if( find_option("set-anon-caps", 0, 0)!=0 ){ |
|
5915e6f…
|
mistachkin
|
3159 |
const char *zCap = fossil_getenv("TH1_TEST_ANON_CAPS"); |
|
5915e6f…
|
mistachkin
|
3160 |
login_set_capabilities(zCap ? zCap : "sx", LOGIN_ANON); |
|
5ea2a4f…
|
mistachkin
|
3161 |
g.useLocalauth = 1; |
|
5ea2a4f…
|
mistachkin
|
3162 |
} |
|
5ea2a4f…
|
mistachkin
|
3163 |
if( find_option("set-user-caps", 0, 0)!=0 ){ |
|
5915e6f…
|
mistachkin
|
3164 |
const char *zCap = fossil_getenv("TH1_TEST_USER_CAPS"); |
|
5915e6f…
|
mistachkin
|
3165 |
login_set_capabilities(zCap ? zCap : "sx", 0); |
|
5ea2a4f…
|
mistachkin
|
3166 |
g.useLocalauth = 1; |
|
5ea2a4f…
|
mistachkin
|
3167 |
} |
|
2116238…
|
drh
|
3168 |
db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0); |
|
f141fbe…
|
mistachkin
|
3169 |
verify_all_options(); |
|
f141fbe…
|
mistachkin
|
3170 |
if( g.argc!=3 ){ |
|
f141fbe…
|
mistachkin
|
3171 |
usage("script"); |
|
f141fbe…
|
mistachkin
|
3172 |
} |
|
6456fab…
|
stephan
|
3173 |
if(file_isfile(g.argv[2], ExtFILE)){ |
|
6456fab…
|
stephan
|
3174 |
blob_read_from_file(&code, g.argv[2], ExtFILE); |
|
6456fab…
|
stephan
|
3175 |
zCode = blob_str(&code); |
|
6456fab…
|
stephan
|
3176 |
}else{ |
|
6456fab…
|
stephan
|
3177 |
zCode = g.argv[2]; |
|
6456fab…
|
stephan
|
3178 |
} |
|
f141fbe…
|
mistachkin
|
3179 |
Th_FossilInit(TH_INIT_DEFAULT); |
|
6456fab…
|
stephan
|
3180 |
rc = Th_Eval(g.interp, 0, zCode, -1); |
|
f141fbe…
|
mistachkin
|
3181 |
zRc = Th_ReturnCodeName(rc, 1); |
|
f141fbe…
|
mistachkin
|
3182 |
fossil_print("%s%s%s\n", zRc, zRc ? ": " : "", Th_GetResult(g.interp, 0)); |
|
f141fbe…
|
mistachkin
|
3183 |
Th_PrintTraceLog(); |
|
6456fab…
|
stephan
|
3184 |
blob_reset(&code); |
|
f141fbe…
|
mistachkin
|
3185 |
if( forceCgi ) cgi_reply(); |
|
f141fbe…
|
mistachkin
|
3186 |
} |
|
f141fbe…
|
mistachkin
|
3187 |
|
|
f141fbe…
|
mistachkin
|
3188 |
/* |
|
f141fbe…
|
mistachkin
|
3189 |
** COMMAND: test-th-source |
|
f141fbe…
|
mistachkin
|
3190 |
** |
|
f141fbe…
|
mistachkin
|
3191 |
** Usage: %fossil test-th-source FILE |
|
f141fbe…
|
mistachkin
|
3192 |
** |
|
f141fbe…
|
mistachkin
|
3193 |
** Evaluate the contents of the file named "FILE" as if it were a header |
|
f141fbe…
|
mistachkin
|
3194 |
** or footer or ticket rendering script and show the results on standard |
|
f141fbe…
|
mistachkin
|
3195 |
** output. |
|
f141fbe…
|
mistachkin
|
3196 |
** |
|
f141fbe…
|
mistachkin
|
3197 |
** Options: |
|
f141fbe…
|
mistachkin
|
3198 |
** --cgi Include a CGI response header in the output |
|
f141fbe…
|
mistachkin
|
3199 |
** --http Include an HTTP response header in the output |
|
f141fbe…
|
mistachkin
|
3200 |
** --open-config Open the configuration database |
|
5ea2a4f…
|
mistachkin
|
3201 |
** --set-anon-caps Set anonymous login capabilities |
|
5ea2a4f…
|
mistachkin
|
3202 |
** --set-user-caps Set user login capabilities |
|
f141fbe…
|
mistachkin
|
3203 |
** --th-trace Trace TH1 execution (for debugging purposes) |
|
817c643…
|
stephan
|
3204 |
** --no-print-result Do not output the final result. Use if it |
|
817c643…
|
stephan
|
3205 |
** interferes with script output. |
|
f141fbe…
|
mistachkin
|
3206 |
*/ |
|
f141fbe…
|
mistachkin
|
3207 |
void test_th_source(void){ |
|
f141fbe…
|
mistachkin
|
3208 |
int rc; |
|
f141fbe…
|
mistachkin
|
3209 |
const char *zRc; |
|
817c643…
|
stephan
|
3210 |
int forceCgi, fullHttpReply, fNoPrintRc; |
|
f141fbe…
|
mistachkin
|
3211 |
Blob in; |
|
924315b…
|
drh
|
3212 |
Th_InitTraceLog(); |
|
924315b…
|
drh
|
3213 |
forceCgi = find_option("cgi", 0, 0)!=0; |
|
924315b…
|
drh
|
3214 |
fullHttpReply = find_option("http", 0, 0)!=0; |
|
817c643…
|
stephan
|
3215 |
fNoPrintRc = find_option("no-print-result",0,0)!=0; |
|
924315b…
|
drh
|
3216 |
if( fullHttpReply ) forceCgi = 1; |
|
924315b…
|
drh
|
3217 |
if( forceCgi ) Th_ForceCgi(fullHttpReply); |
|
924315b…
|
drh
|
3218 |
if( find_option("open-config", 0, 0)!=0 ){ |
|
924315b…
|
drh
|
3219 |
Th_OpenConfig(1); |
|
5ea2a4f…
|
mistachkin
|
3220 |
} |
|
5ea2a4f…
|
mistachkin
|
3221 |
if( find_option("set-anon-caps", 0, 0)!=0 ){ |
|
5915e6f…
|
mistachkin
|
3222 |
const char *zCap = fossil_getenv("TH1_TEST_ANON_CAPS"); |
|
5915e6f…
|
mistachkin
|
3223 |
login_set_capabilities(zCap ? zCap : "sx", LOGIN_ANON); |
|
5ea2a4f…
|
mistachkin
|
3224 |
g.useLocalauth = 1; |
|
5ea2a4f…
|
mistachkin
|
3225 |
} |
|
5ea2a4f…
|
mistachkin
|
3226 |
if( find_option("set-user-caps", 0, 0)!=0 ){ |
|
5915e6f…
|
mistachkin
|
3227 |
const char *zCap = fossil_getenv("TH1_TEST_USER_CAPS"); |
|
5915e6f…
|
mistachkin
|
3228 |
login_set_capabilities(zCap ? zCap : "sx", 0); |
|
5ea2a4f…
|
mistachkin
|
3229 |
g.useLocalauth = 1; |
|
f141fbe…
|
mistachkin
|
3230 |
} |
|
f141fbe…
|
mistachkin
|
3231 |
verify_all_options(); |
|
924315b…
|
drh
|
3232 |
if( g.argc!=3 ){ |
|
f141fbe…
|
mistachkin
|
3233 |
usage("file"); |
|
924315b…
|
drh
|
3234 |
} |
|
f141fbe…
|
mistachkin
|
3235 |
blob_zero(&in); |
|
1772357…
|
drh
|
3236 |
blob_read_from_file(&in, g.argv[2], ExtFILE); |
|
924315b…
|
drh
|
3237 |
Th_FossilInit(TH_INIT_DEFAULT); |
|
f141fbe…
|
mistachkin
|
3238 |
rc = Th_Eval(g.interp, 0, blob_str(&in), -1); |
|
924315b…
|
drh
|
3239 |
zRc = Th_ReturnCodeName(rc, 1); |
|
817c643…
|
stephan
|
3240 |
if(0==fNoPrintRc){ |
|
817c643…
|
stephan
|
3241 |
fossil_print("%s%s%s\n", zRc, zRc ? ": " : "", |
|
817c643…
|
stephan
|
3242 |
Th_GetResult(g.interp, 0)); |
|
817c643…
|
stephan
|
3243 |
} |
|
c1915c3…
|
mistachkin
|
3244 |
Th_PrintTraceLog(); |
|
c1915c3…
|
mistachkin
|
3245 |
if( forceCgi ) cgi_reply(); |
|
1c528d3…
|
mistachkin
|
3246 |
} |
|
1c528d3…
|
mistachkin
|
3247 |
|
|
1c528d3…
|
mistachkin
|
3248 |
#ifdef FOSSIL_ENABLE_TH1_HOOKS |
|
1c528d3…
|
mistachkin
|
3249 |
/* |
|
1c528d3…
|
mistachkin
|
3250 |
** COMMAND: test-th-hook |
|
ddd4cb5…
|
mistachkin
|
3251 |
** |
|
ddd4cb5…
|
mistachkin
|
3252 |
** Usage: %fossil test-th-hook TYPE NAME FLAGS |
|
ddd4cb5…
|
mistachkin
|
3253 |
** |
|
f141fbe…
|
mistachkin
|
3254 |
** Evaluates the TH1 script configured for the pre-operation (i.e. a command |
|
ddd4cb5…
|
mistachkin
|
3255 |
** or web page) "hook" or post-operation "notification". The results of the |
|
ddd4cb5…
|
mistachkin
|
3256 |
** script evaluation, if any, will be printed to the standard output channel. |
|
ddd4cb5…
|
mistachkin
|
3257 |
** The NAME argument must be the name of a command or web page; however, it |
|
ddd4cb5…
|
mistachkin
|
3258 |
** does not necessarily have to be a command or web page that is normally |
|
ddd4cb5…
|
mistachkin
|
3259 |
** recognized by Fossil. The FLAGS argument will be used to set the value |
|
ddd4cb5…
|
mistachkin
|
3260 |
** of the "cmd_flags" and/or "web_flags" TH1 variables, if applicable. The |
|
ddd4cb5…
|
mistachkin
|
3261 |
** TYPE argument must be one of the following: |
|
ddd4cb5…
|
mistachkin
|
3262 |
** |
|
ddd4cb5…
|
mistachkin
|
3263 |
** cmdhook Executes the TH1 procedure [command_hook], after |
|
ddd4cb5…
|
mistachkin
|
3264 |
** setting the TH1 variables "cmd_name", "cmd_args", |
|
ddd4cb5…
|
mistachkin
|
3265 |
** and "cmd_flags" to appropriate values. |
|
ddd4cb5…
|
mistachkin
|
3266 |
** |
|
ddd4cb5…
|
mistachkin
|
3267 |
** cmdnotify Executes the TH1 procedure [command_notify], after |
|
ddd4cb5…
|
mistachkin
|
3268 |
** setting the TH1 variables "cmd_name", "cmd_args", |
|
ddd4cb5…
|
mistachkin
|
3269 |
** and "cmd_flags" to appropriate values. |
|
ddd4cb5…
|
mistachkin
|
3270 |
** |
|
ddd4cb5…
|
mistachkin
|
3271 |
** webhook Executes the TH1 procedure [webpage_hook], after |
|
ddd4cb5…
|
mistachkin
|
3272 |
** setting the TH1 variables "web_name", "web_args", |
|
ddd4cb5…
|
mistachkin
|
3273 |
** and "web_flags" to appropriate values. |
|
ddd4cb5…
|
mistachkin
|
3274 |
** |
|
ddd4cb5…
|
mistachkin
|
3275 |
** webnotify Executes the TH1 procedure [webpage_notify], after |
|
ddd4cb5…
|
mistachkin
|
3276 |
** setting the TH1 variables "web_name", "web_args", |
|
ddd4cb5…
|
mistachkin
|
3277 |
** and "web_flags" to appropriate values. |
|
ddd4cb5…
|
mistachkin
|
3278 |
** |
|
ddd4cb5…
|
mistachkin
|
3279 |
** Options: |
|
ddd4cb5…
|
mistachkin
|
3280 |
** --cgi Include a CGI response header in the output |
|
ddd4cb5…
|
mistachkin
|
3281 |
** --http Include an HTTP response header in the output |
|
ddd4cb5…
|
mistachkin
|
3282 |
** --th-trace Trace TH1 execution (for debugging purposes) |
|
1c528d3…
|
mistachkin
|
3283 |
*/ |
|
1c528d3…
|
mistachkin
|
3284 |
void test_th_hook(void){ |
|
1c528d3…
|
mistachkin
|
3285 |
int rc = TH_OK; |
|
1c528d3…
|
mistachkin
|
3286 |
int nResult = 0; |
|
ddd4cb5…
|
mistachkin
|
3287 |
char *zResult = 0; |
|
c1915c3…
|
mistachkin
|
3288 |
int forceCgi, fullHttpReply; |
|
142200b…
|
mistachkin
|
3289 |
Th_InitTraceLog(); |
|
0afcc93…
|
mistachkin
|
3290 |
forceCgi = find_option("cgi", 0, 0)!=0; |
|
0afcc93…
|
mistachkin
|
3291 |
fullHttpReply = find_option("http", 0, 0)!=0; |
|
0afcc93…
|
mistachkin
|
3292 |
if( fullHttpReply ) forceCgi = 1; |
|
c1915c3…
|
mistachkin
|
3293 |
if( forceCgi ) Th_ForceCgi(fullHttpReply); |
|
f141fbe…
|
mistachkin
|
3294 |
verify_all_options(); |
|
1c528d3…
|
mistachkin
|
3295 |
if( g.argc<5 ){ |
|
1c528d3…
|
mistachkin
|
3296 |
usage("TYPE NAME FLAGS"); |
|
1c528d3…
|
mistachkin
|
3297 |
} |
|
1c528d3…
|
mistachkin
|
3298 |
if( fossil_stricmp(g.argv[2], "cmdhook")==0 ){ |
|
e6aab1a…
|
drh
|
3299 |
rc = Th_CommandHook(g.argv[3], (unsigned int)atoi(g.argv[4])); |
|
1c528d3…
|
mistachkin
|
3300 |
}else if( fossil_stricmp(g.argv[2], "cmdnotify")==0 ){ |
|
e6aab1a…
|
drh
|
3301 |
rc = Th_CommandNotify(g.argv[3], (unsigned int)atoi(g.argv[4])); |
|
1c528d3…
|
mistachkin
|
3302 |
}else if( fossil_stricmp(g.argv[2], "webhook")==0 ){ |
|
e6aab1a…
|
drh
|
3303 |
rc = Th_WebpageHook(g.argv[3], (unsigned int)atoi(g.argv[4])); |
|
1c528d3…
|
mistachkin
|
3304 |
}else if( fossil_stricmp(g.argv[2], "webnotify")==0 ){ |
|
e6aab1a…
|
drh
|
3305 |
rc = Th_WebpageNotify(g.argv[3], (unsigned int)atoi(g.argv[4])); |
|
1c528d3…
|
mistachkin
|
3306 |
}else{ |
|
2c42b21…
|
andygoth
|
3307 |
fossil_fatal("Unknown TH1 hook %s", g.argv[2]); |
|
ddd4cb5…
|
mistachkin
|
3308 |
} |
|
ddd4cb5…
|
mistachkin
|
3309 |
if( g.interp ){ |
|
ddd4cb5…
|
mistachkin
|
3310 |
zResult = (char*)Th_GetResult(g.interp, &nResult); |
|
ddd4cb5…
|
mistachkin
|
3311 |
} |
|
5173701…
|
stephan
|
3312 |
sendText(0,"RESULT (", -1, 0); |
|
5173701…
|
stephan
|
3313 |
sendText(0,Th_ReturnCodeName(rc, 0), -1, 0); |
|
5173701…
|
stephan
|
3314 |
sendText(0,")", -1, 0); |
|
ddd4cb5…
|
mistachkin
|
3315 |
if( zResult && nResult>0 ){ |
|
5173701…
|
stephan
|
3316 |
sendText(0,": ", -1, 0); |
|
5173701…
|
stephan
|
3317 |
sendText(0,zResult, nResult, 0); |
|
ddd4cb5…
|
mistachkin
|
3318 |
} |
|
5173701…
|
stephan
|
3319 |
sendText(0,"\n", -1, 0); |
|
142200b…
|
mistachkin
|
3320 |
Th_PrintTraceLog(); |
|
c1915c3…
|
mistachkin
|
3321 |
if( forceCgi ) cgi_reply(); |
|
588bb7c…
|
aku
|
3322 |
} |
|
1c528d3…
|
mistachkin
|
3323 |
#endif |