Line data Source code
1 : /* Copyright (C) 2000-2003 by George Williams */
2 : /*
3 : * Redistribution and use in source and binary forms, with or without
4 : * modification, are permitted provided that the following conditions are met:
5 :
6 : * Redistributions of source code must retain the above copyright notice, this
7 : * list of conditions and the following disclaimer.
8 :
9 : * Redistributions in binary form must reproduce the above copyright notice,
10 : * this list of conditions and the following disclaimer in the documentation
11 : * and/or other materials provided with the distribution.
12 :
13 : * The name of the author may not be used to endorse or promote products
14 : * derived from this software without specific prior written permission.
15 :
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 : #include "giofuncP.h"
28 : #include <gfile.h>
29 : #include <ustring.h>
30 : #include <errno.h>
31 :
32 : struct stdfuncs _GIO_stdfuncs = {
33 : _GIO_decomposeURL, _GIO_PostSuccess, _GIO_PostInter,
34 : _GIO_PostError, _GIO_RequestAuthorization, _GIO_LookupHost,
35 : NULL, /* default authorizer */
36 : GIOFreeDirEntries,
37 : #ifdef GWW_TEST
38 : _GIO_ReportHeaders, /* set to NULL when not debugging */
39 : #else
40 : NULL,
41 : #endif
42 :
43 : #ifdef HAVE_PTHREAD_H
44 : PTHREAD_MUTEX_INITIALIZER,
45 : #endif
46 : NULL,
47 : NULL
48 : };
49 : static struct protocols {
50 : int index;
51 : unichar_t *proto;
52 : void *handle;
53 : void *(*dispatcher)(GIOControl *gc);
54 : void (*cancel)(GIOControl *gc);
55 : void (*term)(void *);
56 : unsigned int dothread: 1;
57 : } *protocols;
58 : static int plen, pmax;
59 : typedef void *(ptread_startfunc_t)(void *);
60 :
61 : static unichar_t err501[] = { ' ','N','o','t',' ','I','m','p','l','e','m','e','n','t','e','d', '\0' };
62 :
63 0 : static int AddProtocol(unichar_t *prefix,int len) {
64 :
65 0 : if ( plen>=pmax ) {
66 0 : pmax += 20; /* We're never going to support 20 protocols? */
67 0 : if ( plen==0 ) {
68 0 : protocols = (struct protocols *) malloc(pmax*sizeof(struct protocols));
69 : } else {
70 0 : protocols = (struct protocols *) realloc(protocols,pmax*sizeof(struct protocols));
71 : }
72 : }
73 0 : memset(protocols+plen,0,sizeof(struct protocols));
74 0 : if ( uc_strncmp(prefix,"file",len)==0 ) {
75 0 : protocols[plen].handle = NULL;
76 0 : protocols[plen].dispatcher = _GIO_fileDispatch;
77 0 : protocols[plen].cancel = NULL;
78 0 : protocols[plen].term = NULL;
79 0 : protocols[plen].dothread = false;
80 : } else {
81 0 : return( false );
82 : }
83 0 : protocols[plen].index = plen;
84 0 : protocols[plen].proto = u_copyn(prefix,len);
85 0 : ++plen;
86 0 : return( true );
87 : }
88 :
89 0 : static void GIOdispatch(GIOControl *gc, enum giofuncs gf) {
90 : unichar_t *temp, *pt, *tpt;
91 : int i;
92 :
93 0 : gc->gf = gf;
94 :
95 0 : if ( _GIO_stdfuncs.useragent == NULL )
96 0 : _GIO_stdfuncs.useragent = copy("someone@somewhere.com");
97 :
98 0 : temp = _GIO_translateURL(gc->path,gf);
99 0 : if ( temp!=NULL ) {
100 0 : if ( gc->origpath==NULL )
101 0 : gc->origpath = gc->path;
102 : else
103 0 : free(gc->path);
104 0 : gc->path = temp;
105 : }
106 0 : if ( gc->topath!=NULL ) {
107 0 : temp = _GIO_translateURL(gc->topath,gf);
108 0 : if ( temp!=NULL ) {
109 0 : free(gc->topath);
110 0 : gc->topath = temp;
111 : }
112 0 : if ( gf==gf_renamefile ) {
113 0 : if (( pt = uc_strstr(gc->path,"://"))== NULL )
114 0 : pt = gc->path;
115 : else {
116 0 : pt=u_strchr(pt+3,'/');
117 0 : if ( pt==NULL ) pt = gc->path+u_strlen(gc->path);
118 : }
119 0 : if (( tpt = uc_strstr(gc->topath,"://"))== NULL )
120 0 : tpt = gc->topath;
121 : else {
122 0 : tpt=u_strchr(tpt+3,'/');
123 0 : if ( tpt==NULL ) tpt = gc->topath+u_strlen(gc->topath);
124 : }
125 0 : if ( tpt-gc->topath!=pt-gc->path ||
126 0 : u_strnmatch(gc->path,gc->topath,pt-gc->path)!=0 ) {
127 0 : _GIO_reporterror(gc,EXDEV);
128 0 : return;
129 : }
130 : }
131 : }
132 :
133 0 : pt = uc_strstr(gc->path,"://");
134 0 : if ( pt!=NULL ) {
135 0 : for ( i=0; i<plen; ++i )
136 0 : if ( u_strnmatch(protocols[i].proto,gc->path,pt-gc->path)==0 )
137 0 : break;
138 0 : if ( i>=plen && !AddProtocol(gc->path,pt-gc->path) ) {
139 0 : gc->protocol_index = -2;
140 0 : gc->return_code = 501;
141 0 : gc->error = err501;
142 0 : uc_strcpy(gc->status,"No support for browsing: ");
143 0 : u_strncpy(gc->status+u_strlen(gc->status), gc->path, pt-gc->path );
144 0 : gc->done = true;
145 0 : (gc->receiveerror)(gc);
146 0 : return;
147 : }
148 0 : gc->protocol_index = i;
149 0 : if ( !protocols[i].dothread )
150 0 : (protocols[i].dispatcher)(gc);
151 : else {
152 : #ifndef HAVE_PTHREAD_H
153 : gc->return_code = 501;
154 : gc->error = err501;
155 : uc_strcpy(gc->status,"No support for protocol");
156 : gc->done = true;
157 : (gc->receiveerror)(gc);
158 : return;
159 : #else
160 : static pthread_cond_t initcond = PTHREAD_COND_INITIALIZER;
161 : static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER;
162 : /* could put stuff here to queue functions if we get too many */
163 : /* threads, or perhaps even a thread pool */
164 0 : uc_strcpy(gc->status,"Queued");
165 0 : gc->threaddata = (struct gio_threaddata *) malloc(sizeof(struct gio_threaddata));
166 0 : gc->threaddata->mutex = initmutex;
167 0 : gc->threaddata->cond = initcond;
168 0 : if ( _GIO_stdfuncs.gdraw_sync_thread!=NULL )
169 0 : (_GIO_stdfuncs.gdraw_sync_thread)(NULL,NULL,NULL);
170 0 : pthread_create(&gc->threaddata->thread,NULL,
171 0 : (ptread_startfunc_t *) (protocols[i].dispatcher), gc);
172 : #endif
173 : }
174 : } else {
175 0 : gc->protocol_index = -1;
176 0 : _GIO_localDispatch(gc);
177 : }
178 : }
179 :
180 0 : void GIOdir(GIOControl *gc) {
181 0 : GIOdispatch(gc,gf_dir);
182 0 : }
183 :
184 0 : void GIOstatFile(GIOControl *gc) {
185 0 : GIOdispatch(gc,gf_statfile);
186 0 : }
187 :
188 0 : void GIOfileExists(GIOControl *gc) {
189 : /* We can probably do some optimizations here, based on caching and whatnot */
190 0 : GIOdispatch(gc,gf_statfile);
191 0 : }
192 :
193 0 : void GIOmkDir(GIOControl *gc) {
194 0 : GIOdispatch(gc,gf_mkdir);
195 0 : }
196 :
197 0 : void GIOdelFile(GIOControl *gc) {
198 0 : GIOdispatch(gc,gf_delfile);
199 0 : }
200 :
201 0 : void GIOdelDir(GIOControl *gc) {
202 0 : GIOdispatch(gc,gf_deldir);
203 0 : }
204 :
205 0 : void GIOrenameFile(GIOControl *gc) {
206 0 : GIOdispatch(gc,gf_renamefile);
207 0 : }
208 :
209 0 : void GIOFreeDirEntries(GDirEntry *ent) {
210 : GDirEntry *next;
211 :
212 0 : while ( ent!=NULL ) {
213 0 : next = ent->next;
214 0 : free(ent->name);
215 0 : free(ent->mimetype);
216 0 : free(ent);
217 0 : ent = next;
218 : }
219 0 : }
220 :
221 0 : GDirEntry *GIOgetDirData(GIOControl *gc) {
222 :
223 0 : if ( gc->direntrydata )
224 0 : return( (GDirEntry *) gc->iodata );
225 :
226 0 : return( NULL );
227 : }
228 :
229 0 : void GIOcancel(GIOControl *gc) {
230 : #ifdef HAVE_PTHREAD_H
231 0 : if ( gc->protocol_index>=0 && protocols[gc->protocol_index].dothread &&
232 0 : gc->threaddata!=NULL && !gc->done ) {
233 : void *ret;
234 0 : gc->abort = true;
235 0 : pthread_cancel(gc->threaddata->thread);
236 0 : pthread_join(gc->threaddata->thread, &ret);
237 : }
238 : #endif
239 0 : if ( gc->protocol_index>=0 && protocols[gc->protocol_index].cancel!=NULL )
240 : /* Per connection cleanup, cancels io if not done and removes from any queues */
241 0 : (protocols[gc->protocol_index].cancel)(gc);
242 0 : if ( gc->direntrydata )
243 0 : GIOFreeDirEntries((GDirEntry *) gc->iodata);
244 : else
245 0 : free(gc->iodata);
246 0 : free(gc->threaddata);
247 0 : free(gc->path);
248 0 : free(gc->origpath);
249 0 : free(gc->topath);
250 0 : free(gc);
251 0 : }
252 :
253 0 : void GIOclose(GIOControl *gc) {
254 0 : GIOcancel(gc);
255 0 : }
256 :
257 0 : GIOControl *GIOCreate(unichar_t *path,void *userdata,
258 : void (*receivedata)(struct giocontrol *),
259 : void (*receiveerror)(struct giocontrol *)) {
260 0 : GIOControl *gc = (GIOControl *) calloc(1,sizeof(GIOControl));
261 :
262 0 : gc->path = u_copy(path);
263 0 : gc->userdata = userdata;
264 0 : gc->receivedata = receivedata;
265 0 : gc->receiveerror = receiveerror;
266 0 : return(gc);
267 : }
268 :
269 0 : void GIOSetDefAuthorizer(int32 (*getauth)(struct giocontrol *)) {
270 0 : _GIO_stdfuncs.getauth = getauth;
271 0 : }
272 :
273 0 : void GIOSetUserAgent(unichar_t *agent) {
274 0 : free( _GIO_stdfuncs.useragent );
275 0 : _GIO_stdfuncs.useragent = cu_copy(agent);
276 0 : }
277 :
278 0 : void GIO_SetThreadCallback(void (*callback)(void *,void *,void *)) {
279 0 : _GIO_stdfuncs.gdraw_sync_thread = callback;
280 0 : }
|