1 /* retawq/resource.h - resource handling (network, cache, DNS, ...)
2    This file is part of retawq (<http://retawq.sourceforge.net/>), a network
3    client created by Arne Thomassen; retawq is basically released under certain
4    versions of the GNU General Public License and WITHOUT ANY WARRANTY.
5    Read the file COPYING for license details, README for program information.
6    Copyright (C) 2001-2005 Arne Thomassen <arne@arne-thomassen.de>
7 */
8 
9 /* In the comments for data structure declarations in this file, "EXAC(thread)"
10    meant that <thread> is the only thread which may access the marked member
11    in any way ("exclusive access"). For a pointer, EXACD(thread) meant that
12    only that thread may dereference the pointer. */
13 
14 #ifndef __retawq_resource_h__
15 #define __retawq_resource_h__
16 
17 #include "stuff.h"
18 
19 extern /*@observer@*/ const char strRedirection[];
20 
21 #if CAN_HANDLE_SIGNALS
22 extern const_after_init int fd_any2main_read, fd_any2main_write;
23 #endif
24 #if CONFIG_TG == TG_XCURSES
25 extern const_after_init int fd_xcurses2main_read, fd_xcurses2main_write;
26 #endif
27 
28 extern const char strCrlf[];
29 #if CONFIG_FTP
30 extern const char strList[], strRetr[];
31 #endif
32 
33 
34 /* Resource protocols */
35 
36 my_enum1 enum
37 { rpUnknown = 0, rpDisabled = 1, rpHttp = 2, __rpFtp = 3, rpLocal = 4,
38   rpAbout = 5, __rpFinger = 6, __rpLocalCgi = 7, __rpNntp = 8, __rpPop = 9,
39   __rpPops = 10, rpCvs = 11, __rpGopher = 12, rpInfo = 13, __rpMailto = 14,
40   __rpJavascript = 15, __rpHttps = 16, __rpFtps = 17, __rpExecextShell = 18
41 } my_enum2(unsigned char) tResourceProtocol;
42 #define rpMax (18)
43 #define is_rp_nice(rp) ((rp) > rpDisabled)
44 #define MAXSCHEMESTRSIZE ((100) + 1)
45   /* (just a value which is "big enough", even for _(strUnknown)) */
46 
47 #if CONFIG_FINGER
48 #define rpFinger (__rpFinger)
49 #endif
50 #if CONFIG_GOPHER
51 #define rpGopher (__rpGopher)
52 #endif
53 #if CONFIG_FTP
54 #define rpFtp (__rpFtp)
55 #endif
56 #if OPTION_LOCAL_CGI
57 #define rpLocalCgi (__rpLocalCgi)
58 #endif
59 #if OPTION_NEWS
60 #define rpNntp (__rpNntp)
61 #endif
62 #if OPTION_POP
63 #define rpPop (__rpPop)
64 #if OPTION_TLS
65 #define rpPops (__rpPops)
66 #endif
67 #endif
68 #if CONFIG_MAILTO
69 #define rpMailto (__rpMailto)
70 #endif
71 #if CONFIG_JAVASCRIPT
72 #define rpJavascript (__rpJavascript)
73 #endif
74 
75 #if OPTION_TLS
76 #define rpHttps (__rpHttps)
77 #if CONFIG_FTP
78 #define rpFtps  (__rpFtps)
79 #endif
80 #endif
81 
82 #if OPTION_EXECEXT & EXECEXT_SHELL
83 #define rpExecextShell (__rpExecextShell)
84 #endif
85 
86 my_enum1 enum
87 { rpfNone = 0, rpfIsLocallike = 0x01, rpfIsHttplike = 0x02,
88   rpfIsFtplike = 0x04, rpfIsPoplike = 0x08, rpfIsTlslike = 0x10,
89   rpfUsesAuthority = 0x20, rpfIsPathHierarchical = 0x40, rpfUiToupper = 0x80,
90   rpfUiAlternate = 0x100
91 } my_enum2(unsigned short) tRpFlags;
92 
93 typedef struct
94 { const char* scheme;
95   tResourceProtocol final_rp;
96   tRpFlags flags;
97 } tRpData;
98 
99 extern const tRpData rp_data[rpMax + 1];
100 
101 #define __has_rpflag(rp, rpf) (rp_data[(rp)].flags & (rpf))
102 #define is_locallike(rp) __has_rpflag((rp), rpfIsLocallike)
103 #define is_httplike(rp) __has_rpflag((rp), rpfIsHttplike)
104 #if CONFIG_FTP
105 #define is_ftplike(rp) __has_rpflag((rp), rpfIsFtplike)
106 #endif
107 #if OPTION_POP
108 #define is_poplike(rp) __has_rpflag((rp), rpfIsPoplike)
109 #endif
110 #if OPTION_TLS
111 #define is_tlslike(rp) __has_rpflag((rp), rpfIsTlslike)
112 #endif
113 
114 
115 /* Resource data */
116 
117 my_enum1 enum
118 { rfNone = 0, rfFinal = 0x01, rfPost = 0x02, rfIsRedirection = 0x04,
119   rfIsEmbedded = 0x08, rfIsEnforced = 0x10, rfActivityWatched = 0x20,
120   rfActivityUnwatchable = 0x40
121 #if CONFIG_EXTRA & EXTRA_DOWNLOAD
122   , rfDownload = 0x80
123 #endif
124 #if CONFIG_ANY_MAIL
125   , rfMailbox = 0x100
126 #endif
127 #if OPTION_COOKIES
128   , rfCookieSender = 0x200, rfCookieStorer = 0x400 /* RFC2965, 6.1, *2 */
129 #define rfCookieAnything (rfCookieSender | rfCookieStorer)
130 #endif
131 #if CONFIG_CUSTOM_CONN
132   , rfCustomConn = 0x800, rfCustomConnStopSequencer = 0x1000,
133   rfCustomConnBd1 = 0x2000, rfCustomConnBd2 = 0x4000, rfCustomConnBd3 = 0x8000,
134   rfCustomConnBd4 = 0x10000
135 #define rfCustomConnBdAny (rfCustomConnBd1 | rfCustomConnBd2 | rfCustomConnBd3 | rfCustomConnBd4)
136   /* "Bd" as in "Brain-damaged"; the FTP protocol seriously deserves it... */
137 #endif
138 } my_enum2(unsigned int) tResourceFlags;
139 
140 my_enum1 enum
141 { rsUnknown = 0, rsError = 1, rsConnecting = 2, rsMsgExchange = 3,
142   rsReading = 4, rsComplete = 5, rsStopped = 6
143 } my_enum2(unsigned char) tResourceState;
144 #define MAX_RESOURCE_STATE (6)
145 extern /*@observer@*/ const char* const
146   strResourceState[MAX_RESOURCE_STATE + 1];
147 
148 my_enum1 enum
149 { rchUnknown = 0, rchConnected = 1
150 #if CONFIG_FTP
151   , rchFtpUser = 2, rchFtpPassword = 3, rchFtpAccount = 4, rchFtpPasv = 5,
152   rchFtpRequest = 6
153 #if OPTION_TLS
154   , rchFtpTlsAuthTls = 7, rchFtpTlsAuthSsl = 8, rchFtpTlsPbsz = 9,
155   rchFtpTlsProt = 10
156 #endif
157 #if CONFIG_CUSTOM_CONN
158   , rchFtpCustom = 11
159 #endif
160 #endif
161 #if OPTION_NEWS
162   , rchNntpModeReader = 12, rchNntpGetGroups = 13, rchNntpFetchArticle = 14,
163   rchNntpFetchHeader = 15, rchNntpSelectGroup = 16
164 #endif
165 #if OPTION_POP
166   , rchPopUser = 17, rchPopPass = 18, rchPopApop = 19, rchPopStat = 20,
167   rchPopTop = 21, rchPopUidl = 22, rchPopRetr = 23
168 #if OPTION_TLS
169   , rchPopStls = 24
170 #endif
171 #endif
172 } my_enum2(unsigned char) tResourceCommandHandshake;
173 
174 my_enum1 enum
175 { reFine = 0, reKind = 1, reSocket = 2, reConnect = 3, reRefused = 4,
176   reNetwork = 5, reDns = 6, reFile = 7, reUri = 8, reServerClosed = 9,
177   reHandshake = 10, rePortnumber = 11, reProtocol = 12, reTimeout = 13,
178   reResponse = 14, reLogin = 15, reRedirection = 16, reRandom = 17, reTls = 18,
179   reProxyAuth = 19, rePipe = 20, reFork = 21, reConfigForbids = 22,
180   reExec = 23, reProtDisabled = 24, reHostname = 25, reTmofd = 26,
181   reConnReset = 27
182 } my_enum2(unsigned char) tResourceError;
183 #define MAX_RESOURCE_ERROR (27)
184 extern /*@observer@*/ const char* const
185   strResourceError[MAX_RESOURCE_ERROR + 1];
186 
187 #if OPTION_TLS
188 my_enum1 enum
189 { teFine = 0, teUnknown = 1, teSessionExpired = 2, teFatalAlert = 3,
190   teFile = 4, teData = 5, teOom = 6, teCipher = 7, teCompression = 8,
191   teCrypt = 9, teSrp = 10, tePk = 11, tePacket = 12, teUnimplemented = 13,
192   teHandshake = 14, teInit = 15
193 } my_enum2(unsigned char) tTlsError;
194 #define MAX_TLS_ERROR (15)
195 extern /*@observer@*/ const char* const strTlsError[MAX_TLS_ERROR + 1];
196 #define is_tls_error_expressive(te) ((te) > teUnknown) /* for UI */
197 #endif
198 
199 my_enum1 enum
200 { udfNone = 0, udfTryIpv6 = 0x01, udfGotExplicitPortnumber = 0x02
201 #if CONFIG_FTP
202   , udfFtpTypeA = 0x04, udfFtpTypeD = 0x08, udfFtpTypeI = 0x10
203 #endif
204 } my_enum2(unsigned char) tUriDataFlags;
205 
206 typedef struct
207 { char *uri, *hostname, *path, *query, *post, *username, *password;
208   tPortnumber portnumber; /* (in network byte order) */
209   unsigned char refcount; /* 0..2 */
210   tResourceProtocol rp;
211   tResourceError re;
212   tUriDataFlags udf;
213 } tUriData;
214 
215 typedef struct tSaveAs
216 { struct tSaveAs* next;
217   int fd;
218 } tSaveAs;
219 
220 typedef unsigned short tServerStatusCode; /* 0 or roughly 100..699 */
221 typedef signed char tTlHeaderState; /*transport-level header state (misnomer)*/
222 
223 #define UNKNOWN_CONTENTLENGTH ((size_t) (~((size_t) 0)))
224 
225 #if 1 || CONFIG_FTP || OPTION_NEWS || OPTION_POP || OPTION_TRAP
226 /* (the "1 ||" is for HTTP nowadays) */
227 #define USE_RPSD 1
228 struct tRpsdGeneric; /* resource-protocol-specific data */
229 #else
230 #define USE_RPSD 0
231 #endif
232 
233 typedef struct tTransferData
234 { struct tTransferData* next;
235   const char* name;
236   char* data;
237   size_t size;
238   tBoolean need_unmap;
239 } tTransferData;
240 
241 my_enum1 enum
242 { sdfNone = 0, sdfIsDownloadFdValid = 0x01, sdfIsRestartMarkerValid = 0x02
243 } my_enum2(unsigned char) tSinkingDataFlags;
244 
245 typedef struct
246 { tTransferData* transfer_data;
247   size_t restart_marker;
248   int download_fd;
249   tSinkingDataFlags flags;
250 } tSinkingData;
251 /* data which "sinks" from the high-level user interface over tResourceRequest
252    to the low-level networking code */
253 
254 struct tConnection;
255 
256 typedef struct tResource
257 { struct tResource *next, *prev; /* for the RAM cache; EXAC(resource) */
258   struct tConnection *cconn, *dconn; /* control/data; EXAC(resource) */
259   tCantent* cantent;
260   tUriData* uri_data;
261   tDhmGenericData* dhm_data;
262   const tConfigProxy* proxy;
263   struct tHostPortProtInfo *actual_hppi, *textual_hppi; /* EXAC(resource) */
264     /* (might differ, e.g. when proxies are used; textual_hppi always holds
265         stuff which originates from the URI) */
266   tSinkingData* sinking_data;
267   tSaveAs* save_as; /* for saving to disk; EXAC(resource) */
268 #if USE_RPSD
269   struct tRpsdGeneric* rpsd; /* EXAC(resource) */
270 #endif
271 #if CONFIG_CUSTOM_CONN
272   void* custconn_handle; /* tConsoleTaskNum or tWindow* */
273 #endif
274   size_t nominal_contentlength;
275   size_t bytecount; /* roughly "number of bytes in document" */
276   tResourceFlags flags;
277   tServerStatusCode server_status_code; /* (FTP terminology: reply code) */
278   tTlHeaderState tlheaderstate; /* EXAC(resource) */
279   tResourceProtocol protocol;
280   tResourceState state;
281   tResourceCommandHandshake handshake;
282   tResourceError error;
283 #if OPTION_TLS
284   tTlsError tls_error; /* used if ->error == reTls */
285 #endif
286 } tResource;
287 
288 
289 /* Resource requests */
290 
291 my_enum1 enum
292 { rraLoad = 0, rraReload = 1, rraEnforcedReload = 2
293 #if CONFIG_CUSTOM_CONN
294   , rraCustomConn = 3
295 #endif
296 } my_enum2(unsigned char) tResourceRequestAction;
297 
298 #define is_loadrra(rra) \
299   ( ((rra) == rraLoad) || ((rra) == rraReload) || ((rra) == rraEnforcedReload))
300 
301 my_enum1 enum
302 { rrsUnknown = 0, rrsError = 1, rrsPreparedByMain = 2, rrsAttachedResource = 3,
303   rrsStopped = 4
304 #if CONFIG_ASYNC_DNS
305   , rrsDnsLookup = 5
306 #endif
307 } my_enum2(unsigned char) tResourceRequestState;
308 #define MAX_RESOURCE_REQUEST_STATE (5)
309 extern /*@observer@*/ const char* const
310   strResourceRequestState[MAX_RESOURCE_REQUEST_STATE + 1];
311 
312 my_enum1 enum
313 { rrfNone = 0, rrfResourceChanged = 0x01, rrfPost = 0x02,
314   rrfIsRedirection = 0x04, rrfIsEmbedded = 0x08
315 #if CONFIG_EXTRA & EXTRA_DOWNLOAD
316   , rrfDownload = 0x10
317 #endif
318 } my_enum2(unsigned char) tResourceRequestFlags;
319 
320 struct tCachedHostInformation;
321 
322 typedef struct
323 { tUriData* uri_data;
324   tDhmGenericData* dhm_data; /* (non-refcounted) */
325   const tConfigProxy* proxy; /* EXAC(resource) */
326   tResource* resource; /* the result of the request */
327   struct tCachedHostInformation* lookup; /* EXAC(resource) */
328   tSinkingData* sinking_data;
329   tResourceRequestFlags flags;
330   tResourceRequestAction action;
331   tResourceRequestState state;
332   tResourceError error;
333 } tResourceRequest;
334 
335 
336 /* User queries */
337 
338 #if CONFIG_USER_QUERY
339 
340 my_enum1 enum
341 { mifNone = 0, mifQueryFailed = 0x01, mifUserCancelled = 0x02,
342   mifObjectVanished = 0x04, mifProxyrelated = 0x08,
343   mifPriorLoginAttemptFailed = 0x10, mifUsername = 0x20, mifPassword = 0x40,
344   mifAccount = 0x80, mifSharedSecret = 0x100
345 #if CONFIG_FTP && OPTION_TLS
346   , mifFtpsDataclear = 0x200
347 #endif
348 } my_enum2(unsigned short) tMissingInformationFlags;
349 #define mifSet (mifUsername | mifPassword | mifAccount | mifSharedSecret)
350 
351 struct tUserQuery;
352 typedef void (*tUserQueryCallback)(struct tUserQuery*);
353 typedef struct tUserQuery
354 { tUserQueryCallback callback; /* a function in resource.c */
355   tResource* resource;
356   struct tHostPortProtInfo* hppi; /* EXAC(resource) */
357   const char* hostname; /* (just a pointer copy, no strdup()ing necessary) */
358   tPortnumber portnumber; /* (in network byte order) */
359   tMissingInformationFlags mif;
360 } tUserQuery;
361 
362 extern void user_query_queue(tUserQuery*); /* see main.c */
363 
364 #else
365 
366 typedef struct { unsigned char dummy; } tUserQuery;
367 
368 #endif
369 
370 
371 /* Execution of shell commands */
372 
373 #if OPTION_EXECEXT & EXECEXT_SHELL
374 
375 my_enum1 enum
376 { esfNone = 0, esfReadStdout = 0x01, esfReadStderr = 0x02,
377   esfEnforceHtml = 0x04
378 } my_enum2(unsigned char) tExecextShellFlags;
379 
380 typedef struct
381 { tResourceRequest* request;
382   const char *command, *writedata;
383   size_t writedata_size;
384   tExecextShellFlags esf;
385 } tExecextShellData;
386 
387 extern void resource_start_execext_shell(tExecextShellData*);
388 
389 #endif
390 
391 
392 /* Custom connections */
393 
394 #if CONFIG_CUSTOM_CONN
395 
396 my_enum1 enum
397 { ccpkNormal = 0, ccpkError = 1, ccpkNetcmd = 2, ccpkNetresp = 3
398 } my_enum2(unsigned char) tCustomConnPrintingKind;
399 
400 typedef struct
401 { const char* text;
402   size_t len; /* (only needed for ccpkNetresp) */
403   tCustomConnPrintingKind ccpk;
404 } tCustomConnPrintingData;
405 
406 extern void resource_custom_conn_start(tResource*, unsigned char, const void*);
407 
408 extern void main_handle_custom_conn(tResource*, unsigned char, void*);
409   /* see main.c */
410 
411 #endif
412 
413 
414 /* Functions */
415 
416 extern tPortnumber rp2portnumber(tResourceProtocol);
417 extern void rp2scheme(tResourceProtocol, /*@out@*/ char*);
418 extern void resource_preplex(void);
419 extern void resource_postplex(void);
420 extern void resource_request_start(tResourceRequest*);
421 extern void resource_request_stop(tResourceRequest*);
422 extern void resource_start_saving(tResource*, const tCantent*, int);
423 extern void uri_put(tUriData*);
424 #define uri_attach(dest, u) do { (u)->refcount++; (dest) = (u); } while (0)
425 #define uri_detach(u) do { uri_put(u); (u) = NULL; } while (0)
426 extern tCantent* cantent_create(void);
427 extern void cantent_put(tCantent*);
428 #define cantent_attach(dest, c) do { (c)->refcount++; (dest) = (c); } while (0)
429 #define cantent_detach(c) do { cantent_put(c); (c) = NULL; } while (0)
430 extern void cantent_collect_str(tCantent*, const char*);
431 extern void cantent_collect_title(tCantent*, const char*);
432 extern void sinking_data_cleanup(tSinkingData*);
433 extern void sinking_data_deallocate(tSinkingData**);
434 
435 extern const char* htmlify(const char*);
436 #define htmlify_cleanup(orig, htmlified) \
437   do { if (htmlified != orig) memory_deallocate(htmlified); } while (0)
438 
439 #if CONFIG_BLOAT & BLOAT_SSC
440 extern /*@observer@*/ const char* ssc2info(tResourceProtocol,
441   tServerStatusCode);
442 #else
443 #define ssc2info(rp, ssc) (strEmpty)
444 #endif
445 
446 #define USE_S2U ((CONFIG_BLOAT & BLOAT_UIIP) || (CONFIG_DEBUG))
447 #if USE_S2U
448 extern tBoolean resource_ui_conn_ip(const tResource*, /*@out@*/ char*, size_t);
449 #else
450 #define resource_ui_conn_ip(res, buf, size) (falsE)
451 #endif
452 
453 #if OPTION_TLS
454 extern tBoolean resource_in_tls(const tResource*, tBoolean);
455 #endif
456 
457 extern void resource_initialize(void);
458 extern void resource_quit(void);
459 
460 #endif /* #ifndef __retawq_resource_h__ */
461