HTFile.c 74 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059
  1. /* File Access HTFile.c
  2. * ===========
  3. *
  4. * This is unix-specific code in general, with some VMS bits.
  5. * These are routines for file access used by browsers.
  6. * Development of this module for Unix DIRED_SUPPORT in Lynx
  7. * regrettably has has been conducted in a manner with now
  8. * creates a major impediment for hopes of adapting Lynx to
  9. * a newer version of the library.
  10. *
  11. * History:
  12. * Feb 91 Written Tim Berners-Lee CERN/CN
  13. * Apr 91 vms-vms access included using DECnet syntax
  14. * 26 Jun 92 (JFG) When running over DECnet, suppressed FTP.
  15. * Fixed access bug for relative names on VMS.
  16. * Sep 93 (MD) Access to VMS files allows sharing.
  17. * 15 Nov 93 (MD) Moved HTVMSname to HTVMSUTILS.C
  18. * 27 Dec 93 (FM) FTP now works with VMS hosts.
  19. * FTP path must be Unix-style and cannot include
  20. * the device or top directory.
  21. */
  22. #include <HTUtils.h>
  23. #ifndef VMS
  24. #if defined(DOSPATH)
  25. #undef LONG_LIST
  26. #define LONG_LIST /* Define this for long style unix listings (ls -l),
  27. the actual style is configurable from lynx.cfg */
  28. #endif
  29. /* #define NO_PARENT_DIR_REFERENCE *//* Define this for no parent links */
  30. #endif /* !VMS */
  31. #if defined(DOSPATH)
  32. #define HAVE_READDIR 1
  33. #define USE_DIRENT
  34. #endif
  35. #if defined(USE_DOS_DRIVES)
  36. #include <HTDOS.h>
  37. #endif
  38. #include <HTFile.h> /* Implemented here */
  39. #ifdef VMS
  40. #include <stat.h>
  41. #endif /* VMS */
  42. #if defined (USE_ZLIB) || defined (USE_BZLIB)
  43. #include <GridText.h>
  44. #endif
  45. #define MULTI_SUFFIX ".multi" /* Extension for scanning formats */
  46. #include <HTParse.h>
  47. #include <HTTCP.h>
  48. #ifndef DECNET
  49. #include <HTFTP.h>
  50. #endif /* !DECNET */
  51. #include <HTAnchor.h>
  52. #include <HTAtom.h>
  53. #include <HTAAProt.h>
  54. #include <HTFWriter.h>
  55. #include <HTInit.h>
  56. #include <HTBTree.h>
  57. #include <HTAlert.h>
  58. #include <HTCJK.h>
  59. #include <UCDefs.h>
  60. #include <UCMap.h>
  61. #include <UCAux.h>
  62. #include <LYexit.h>
  63. #include <LYCharSets.h>
  64. #include <LYGlobalDefs.h>
  65. #include <LYStrings.h>
  66. #include <LYUtils.h>
  67. #ifdef USE_PRETTYSRC
  68. # include <LYPrettySrc.h>
  69. #endif
  70. #include <LYLeaks.h>
  71. typedef struct _HTSuffix {
  72. char *suffix;
  73. HTAtom *rep;
  74. HTAtom *encoding;
  75. char *desc;
  76. float quality;
  77. } HTSuffix;
  78. typedef struct {
  79. struct stat file_info;
  80. char sort_tags;
  81. char file_name[1]; /* on the end of the struct, since its length varies */
  82. } DIRED;
  83. #ifndef NGROUPS
  84. #ifdef NGROUPS_MAX
  85. #define NGROUPS NGROUPS_MAX
  86. #else
  87. #define NGROUPS 32
  88. #endif /* NGROUPS_MAX */
  89. #endif /* NGROUPS */
  90. #ifndef GETGROUPS_T
  91. #define GETGROUPS_T int
  92. #endif
  93. #include <HTML.h> /* For directory object building */
  94. #define PUTC(c) (*target->isa->put_character)(target, c)
  95. #define PUTS(s) (*target->isa->put_string)(target, s)
  96. #define START(e) (*target->isa->start_element)(target, e, 0, 0, -1, 0)
  97. #define END(e) (*target->isa->end_element)(target, e, 0)
  98. #define MAYBE_END(e) if (HTML_dtd.tags[e].contents != SGML_EMPTY) \
  99. (*target->isa->end_element)(target, e, 0)
  100. #define FREE_TARGET (*target->isa->_free)(target)
  101. #define ABORT_TARGET (*targetClass._abort)(target, NULL);
  102. struct _HTStructured {
  103. const HTStructuredClass *isa;
  104. /* ... */
  105. };
  106. /*
  107. * Controlling globals.
  108. */
  109. int HTDirAccess = HT_DIR_OK;
  110. #ifdef DIRED_SUPPORT
  111. int HTDirReadme = HT_DIR_README_NONE;
  112. #else
  113. int HTDirReadme = HT_DIR_README_TOP;
  114. #endif /* DIRED_SUPPORT */
  115. static const char *HTMountRoot = "/Net/"; /* Where to find mounts */
  116. #ifdef VMS
  117. static const char *HTCacheRoot = "/WWW$SCRATCH"; /* Where to cache things */
  118. #else
  119. static const char *HTCacheRoot = "/tmp/W3_Cache_"; /* Where to cache things */
  120. #endif /* VMS */
  121. /*
  122. * Suffix registration.
  123. */
  124. static HTList *HTSuffixes = 0;
  125. static HTSuffix no_suffix =
  126. {"*", NULL, NULL, NULL, 1.0};
  127. static HTSuffix unknown_suffix =
  128. {"*.*", NULL, NULL, NULL, 1.0};
  129. /* To free up the suffixes at program exit.
  130. * ----------------------------------------
  131. */
  132. #ifdef LY_FIND_LEAKS
  133. static void free_suffixes(void);
  134. #endif
  135. #ifdef LONG_LIST
  136. static char *FormatStr(char **bufp,
  137. char *start,
  138. const char *entry)
  139. {
  140. char fmt[512];
  141. if (*start) {
  142. sprintf(fmt, "%%%.*ss", (int) sizeof(fmt) - 3, start);
  143. HTSprintf0(bufp, fmt, entry);
  144. } else if (*bufp && !(entry && *entry)) {
  145. **bufp = '\0';
  146. } else if (entry) {
  147. StrAllocCopy(*bufp, entry);
  148. }
  149. return *bufp;
  150. }
  151. static char *FormatNum(char **bufp,
  152. char *start,
  153. int entry)
  154. {
  155. char fmt[512];
  156. if (*start) {
  157. sprintf(fmt, "%%%.*sd", (int) sizeof(fmt) - 3, start);
  158. HTSprintf0(bufp, fmt, entry);
  159. } else {
  160. sprintf(fmt, "%d", entry);
  161. StrAllocCopy(*bufp, fmt);
  162. }
  163. return *bufp;
  164. }
  165. static void LYListFmtParse(const char *fmtstr,
  166. DIRED * data,
  167. char *file,
  168. HTStructured * target,
  169. char *tail)
  170. {
  171. char c;
  172. char *s;
  173. char *end;
  174. char *start;
  175. char *str = NULL;
  176. char *buf = NULL;
  177. char tmp[LY_MAXPATH];
  178. char type;
  179. #ifndef NOUSERS
  180. const char *name;
  181. #endif
  182. time_t now;
  183. char *datestr;
  184. #ifdef S_IFLNK
  185. int len;
  186. #endif
  187. #define SEC_PER_YEAR (60 * 60 * 24 * 365)
  188. #ifdef _WINDOWS /* 1998/01/06 (Tue) 21:20:53 */
  189. static const char *pbits[] =
  190. {
  191. "---", "--x", "-w-", "-wx",
  192. "r--", "r-x", "rw-", "rwx",
  193. 0};
  194. #define PBIT(a, n, s) pbits[((a) >> (n)) & 0x7]
  195. #else
  196. static const char *pbits[] =
  197. {"---", "--x", "-w-", "-wx",
  198. "r--", "r-x", "rw-", "rwx", 0};
  199. static const char *psbits[] =
  200. {"--S", "--s", "-wS", "-ws",
  201. "r-S", "r-s", "rwS", "rws", 0};
  202. #define PBIT(a, n, s) (s) ? psbits[((a) >> (n)) & 0x7] : \
  203. pbits[((a) >> (n)) & 0x7]
  204. #endif
  205. #ifdef S_ISVTX
  206. static const char *ptbits[] =
  207. {"--T", "--t", "-wT", "-wt",
  208. "r-T", "r-t", "rwT", "rwt", 0};
  209. #define PTBIT(a, s) (s) ? ptbits[(a) & 0x7] : pbits[(a) & 0x7]
  210. #else
  211. #define PTBIT(a, s) PBIT(a, 0, 0)
  212. #endif
  213. if (data->file_info.st_mode == 0)
  214. fmtstr = " %a"; /* can't stat so just do anchor */
  215. StrAllocCopy(str, fmtstr);
  216. s = str;
  217. end = str + strlen(str);
  218. while (*s) {
  219. start = s;
  220. while (*s) {
  221. if (*s == '%') {
  222. if (*(s + 1) == '%') /* literal % */
  223. s++;
  224. else
  225. break;
  226. }
  227. s++;
  228. }
  229. /* s is positioned either at a % or at \0 */
  230. *s = '\0';
  231. if (s > start) { /* some literal chars. */
  232. PUTS(start);
  233. }
  234. if (s == end)
  235. break;
  236. start = ++s;
  237. while (isdigit(UCH(*s)) || *s == '.' || *s == '-' || *s == ' ' ||
  238. *s == '#' || *s == '+' || *s == '\'')
  239. s++;
  240. c = *s; /* the format char. or \0 */
  241. *s = '\0';
  242. switch (c) {
  243. case '\0':
  244. PUTS(start);
  245. continue;
  246. case 'A':
  247. case 'a': /* anchor */
  248. HTDirEntry(target, tail, data->file_name);
  249. FormatStr(&buf, start, data->file_name);
  250. PUTS(buf);
  251. END(HTML_A);
  252. *buf = '\0';
  253. #ifdef S_IFLNK
  254. if (c != 'A' && S_ISLNK(data->file_info.st_mode) &&
  255. (len = readlink(file, tmp, sizeof(tmp) - 1)) >= 0) {
  256. PUTS(" -> ");
  257. tmp[len] = '\0';
  258. PUTS(tmp);
  259. }
  260. #endif
  261. break;
  262. case 'T': /* MIME type */
  263. case 't': /* MIME type description */
  264. if (S_ISDIR(data->file_info.st_mode)) {
  265. if (c != 'T') {
  266. FormatStr(&buf, start, ENTRY_IS_DIRECTORY);
  267. } else {
  268. FormatStr(&buf, start, "");
  269. }
  270. } else {
  271. const char *cp2;
  272. HTFormat format;
  273. format = HTFileFormat(file, NULL, &cp2);
  274. if (c != 'T') {
  275. if (cp2 == NULL) {
  276. if (!strncmp(HTAtom_name(format),
  277. "application", 11)) {
  278. cp2 = HTAtom_name(format) + 12;
  279. if (!strncmp(cp2, "x-", 2))
  280. cp2 += 2;
  281. } else {
  282. cp2 = HTAtom_name(format);
  283. }
  284. }
  285. FormatStr(&buf, start, cp2);
  286. } else {
  287. FormatStr(&buf, start, HTAtom_name(format));
  288. }
  289. }
  290. break;
  291. case 'd': /* date */
  292. now = time(0);
  293. datestr = ctime(&data->file_info.st_mtime);
  294. if ((now - data->file_info.st_mtime) < SEC_PER_YEAR / 2)
  295. /*
  296. * MMM DD HH:MM
  297. */
  298. sprintf(tmp, "%.12s", datestr + 4);
  299. else
  300. /*
  301. * MMM DD YYYY
  302. */
  303. sprintf(tmp, "%.7s %.4s ", datestr + 4,
  304. datestr + 20);
  305. FormatStr(&buf, start, tmp);
  306. break;
  307. case 's': /* size in bytes */
  308. FormatNum(&buf, start, (int) data->file_info.st_size);
  309. break;
  310. case 'K': /* size in Kilobytes but not for directories */
  311. if (S_ISDIR(data->file_info.st_mode)) {
  312. FormatStr(&buf, start, "");
  313. StrAllocCat(buf, " ");
  314. break;
  315. }
  316. /* FALL THROUGH */
  317. case 'k': /* size in Kilobytes */
  318. FormatNum(&buf, start, (int) ((data->file_info.st_size + 1023) / 1024));
  319. StrAllocCat(buf, "K");
  320. break;
  321. case 'p': /* unix-style permission bits */
  322. switch (data->file_info.st_mode & S_IFMT) {
  323. #if defined(_MSC_VER) && defined(_S_IFIFO)
  324. case _S_IFIFO:
  325. type = 'p';
  326. break;
  327. #else
  328. case S_IFIFO:
  329. type = 'p';
  330. break;
  331. #endif
  332. case S_IFCHR:
  333. type = 'c';
  334. break;
  335. case S_IFDIR:
  336. type = 'd';
  337. break;
  338. case S_IFREG:
  339. type = '-';
  340. break;
  341. #ifdef S_IFBLK
  342. case S_IFBLK:
  343. type = 'b';
  344. break;
  345. #endif
  346. #ifdef S_IFLNK
  347. case S_IFLNK:
  348. type = 'l';
  349. break;
  350. #endif
  351. #ifdef S_IFSOCK
  352. # ifdef S_IFIFO /* some older machines (e.g., apollo) have a conflict */
  353. # if S_IFIFO != S_IFSOCK
  354. case S_IFSOCK:
  355. type = 's';
  356. break;
  357. # endif
  358. # else
  359. case S_IFSOCK:
  360. type = 's';
  361. break;
  362. # endif
  363. #endif /* S_IFSOCK */
  364. default:
  365. type = '?';
  366. break;
  367. }
  368. #ifdef _WINDOWS
  369. sprintf(tmp, "%c%s", type,
  370. PBIT(data->file_info.st_mode, 6, data->file_info.st_mode & S_IRWXU));
  371. #else
  372. sprintf(tmp, "%c%s%s%s", type,
  373. PBIT(data->file_info.st_mode, 6, data->file_info.st_mode & S_ISUID),
  374. PBIT(data->file_info.st_mode, 3, data->file_info.st_mode & S_ISGID),
  375. PTBIT(data->file_info.st_mode, data->file_info.st_mode & S_ISVTX));
  376. #endif
  377. FormatStr(&buf, start, tmp);
  378. break;
  379. case 'o': /* owner */
  380. #ifndef NOUSERS
  381. name = HTAA_UidToName(data->file_info.st_uid);
  382. if (*name) {
  383. FormatStr(&buf, start, name);
  384. } else {
  385. FormatNum(&buf, start, (int) data->file_info.st_uid);
  386. }
  387. #endif
  388. break;
  389. case 'g': /* group */
  390. #ifndef NOUSERS
  391. name = HTAA_GidToName(data->file_info.st_gid);
  392. if (*name) {
  393. FormatStr(&buf, start, name);
  394. } else {
  395. FormatNum(&buf, start, (int) data->file_info.st_gid);
  396. }
  397. #endif
  398. break;
  399. case 'l': /* link count */
  400. FormatNum(&buf, start, (int) data->file_info.st_nlink);
  401. break;
  402. case '%': /* literal % with flags/width */
  403. FormatStr(&buf, start, "%");
  404. break;
  405. default:
  406. fprintf(stderr,
  407. "Unknown format character `%c' in list format\n", c);
  408. break;
  409. }
  410. if (buf)
  411. PUTS(buf);
  412. s++;
  413. }
  414. FREE(buf);
  415. PUTC('\n');
  416. FREE(str);
  417. }
  418. #endif /* LONG_LIST */
  419. /* Define the representation associated with a file suffix.
  420. * --------------------------------------------------------
  421. *
  422. * Calling this with suffix set to "*" will set the default
  423. * representation.
  424. * Calling this with suffix set to "*.*" will set the default
  425. * representation for unknown suffix files which contain a ".".
  426. *
  427. * The encoding parameter can give a trivial (8bit, 7bit, binary)
  428. * or real (gzip, compress) encoding.
  429. *
  430. * If filename suffix is already defined with the same encoding
  431. * its previous definition is overridden.
  432. */
  433. void HTSetSuffix5(const char *suffix,
  434. const char *representation,
  435. const char *encoding,
  436. const char *desc,
  437. double value)
  438. {
  439. HTSuffix *suff;
  440. BOOL trivial_enc = (BOOL) IsUnityEncStr(encoding);
  441. if (strcmp(suffix, "*") == 0)
  442. suff = &no_suffix;
  443. else if (strcmp(suffix, "*.*") == 0)
  444. suff = &unknown_suffix;
  445. else {
  446. HTList *cur = HTSuffixes;
  447. while (NULL != (suff = (HTSuffix *) HTList_nextObject(cur))) {
  448. if (suff->suffix && 0 == strcmp(suff->suffix, suffix) &&
  449. ((trivial_enc && IsUnityEnc(suff->encoding)) ||
  450. (!trivial_enc && !IsUnityEnc(suff->encoding) &&
  451. strcmp(encoding, HTAtom_name(suff->encoding)) == 0)))
  452. break;
  453. }
  454. if (!suff) { /* Not found -- create a new node */
  455. suff = typecalloc(HTSuffix);
  456. if (suff == NULL)
  457. outofmem(__FILE__, "HTSetSuffix");
  458. /*
  459. * Memory leak fixed.
  460. * 05-28-94 Lynx 2-3-1 Garrett Arch Blythe
  461. */
  462. if (!HTSuffixes) {
  463. HTSuffixes = HTList_new();
  464. #ifdef LY_FIND_LEAKS
  465. atexit(free_suffixes);
  466. #endif
  467. }
  468. HTList_addObject(HTSuffixes, suff);
  469. StrAllocCopy(suff->suffix, suffix);
  470. }
  471. }
  472. if (representation)
  473. suff->rep = HTAtom_for(representation);
  474. /*
  475. * Memory leak fixed.
  476. * 05-28-94 Lynx 2-3-1 Garrett Arch Blythe
  477. * Invariant code removed.
  478. */
  479. suff->encoding = HTAtom_for(encoding);
  480. StrAllocCopy(suff->desc, desc);
  481. suff->quality = (float) value;
  482. }
  483. #ifdef LY_FIND_LEAKS
  484. /*
  485. * Purpose: Free all added suffixes.
  486. * Arguments: void
  487. * Return Value: void
  488. * Remarks/Portability/Dependencies/Restrictions:
  489. * To be used at program exit.
  490. * Revision History:
  491. * 05-28-94 created Lynx 2-3-1 Garrett Arch Blythe
  492. */
  493. static void free_suffixes(void)
  494. {
  495. HTSuffix *suff = NULL;
  496. /*
  497. * Loop through all suffixes.
  498. */
  499. while (!HTList_isEmpty(HTSuffixes)) {
  500. /*
  501. * Free off each item and its members if need be.
  502. */
  503. suff = (HTSuffix *) HTList_removeLastObject(HTSuffixes);
  504. FREE(suff->suffix);
  505. FREE(suff->desc);
  506. FREE(suff);
  507. }
  508. /*
  509. * Free off the list itself.
  510. */
  511. HTList_delete(HTSuffixes);
  512. HTSuffixes = NULL;
  513. }
  514. #endif /* LY_FIND_LEAKS */
  515. /* Make the cache file name for a W3 document.
  516. * -------------------------------------------
  517. * Make up a suitable name for saving the node in
  518. *
  519. * E.g. /tmp/WWW_Cache_news/1234@cernvax.cern.ch
  520. * /tmp/WWW_Cache_http/crnvmc/FIND/xx.xxx.xx
  521. *
  522. * On exit:
  523. * Returns a malloc'ed string which must be freed by the caller.
  524. */
  525. char *HTCacheFileName(const char *name)
  526. {
  527. char *acc_method = HTParse(name, "", PARSE_ACCESS);
  528. char *host = HTParse(name, "", PARSE_HOST);
  529. char *path = HTParse(name, "", PARSE_PATH + PARSE_PUNCTUATION);
  530. char *result = NULL;
  531. HTSprintf0(&result, "%s/WWW/%s/%s%s", HTCacheRoot, acc_method, host, path);
  532. FREE(path);
  533. FREE(acc_method);
  534. FREE(host);
  535. return result;
  536. }
  537. /* Open a file for write, creating the path.
  538. * -----------------------------------------
  539. */
  540. #ifdef NOT_IMPLEMENTED
  541. static int HTCreatePath(const char *path)
  542. {
  543. return -1;
  544. }
  545. #endif /* NOT_IMPLEMENTED */
  546. /* Convert filename from URL-path syntax to local path format
  547. * ----------------------------------------------------------
  548. * Input name is assumed to be the URL-path of a local file
  549. * URL, i.e. what comes after the "file://localhost".
  550. * '#'-fragments to be treated as such must already be stripped.
  551. * If expand_all is FALSE, unescape only escaped '/'. - kw
  552. *
  553. * On exit:
  554. * Returns a malloc'ed string which must be freed by the caller.
  555. */
  556. char *HTURLPath_toFile(const char *name,
  557. BOOL expand_all,
  558. BOOL is_remote GCC_UNUSED)
  559. {
  560. char *path = NULL;
  561. char *result = NULL;
  562. StrAllocCopy(path, name);
  563. if (expand_all)
  564. HTUnEscape(path); /* Interpret all % signs */
  565. else
  566. HTUnEscapeSome(path, "/"); /* Interpret % signs for path delims */
  567. CTRACE((tfp, "URLPath `%s' means path `%s'\n", name, path));
  568. #if defined(USE_DOS_DRIVES)
  569. StrAllocCopy(result, is_remote ? path : HTDOS_name(path));
  570. #else
  571. StrAllocCopy(result, path);
  572. #endif
  573. FREE(path);
  574. return result;
  575. }
  576. /* Convert filenames between local and WWW formats.
  577. * ------------------------------------------------
  578. * Make up a suitable name for saving the node in
  579. *
  580. * E.g. $(HOME)/WWW/news/1234@cernvax.cern.ch
  581. * $(HOME)/WWW/http/crnvmc/FIND/xx.xxx.xx
  582. *
  583. * On exit:
  584. * Returns a malloc'ed string which must be freed by the caller.
  585. */
  586. /* NOTE: Don't use this function if you know that the input is a URL path
  587. rather than a full URL, use HTURLPath_toFile instead. Otherwise
  588. this function will return the wrong thing for some unusual
  589. paths (like ones containing "//", possibly escaped). - kw
  590. */
  591. char *HTnameOfFile_WWW(const char *name,
  592. BOOL WWW_prefix,
  593. BOOL expand_all)
  594. {
  595. char *acc_method = HTParse(name, "", PARSE_ACCESS);
  596. char *host = HTParse(name, "", PARSE_HOST);
  597. char *path = HTParse(name, "", PARSE_PATH + PARSE_PUNCTUATION);
  598. const char *home;
  599. char *result = NULL;
  600. if (expand_all) {
  601. HTUnEscape(path); /* Interpret all % signs */
  602. } else
  603. HTUnEscapeSome(path, "/"); /* Interpret % signs for path delims */
  604. if (0 == strcmp(acc_method, "file") /* local file */
  605. ||!*acc_method) { /* implicitly local? */
  606. if ((0 == strcasecomp(host, HTHostName())) ||
  607. (0 == strcasecomp(host, "localhost")) || !*host) {
  608. CTRACE((tfp, "Node `%s' means path `%s'\n", name, path));
  609. StrAllocCopy(result, HTSYS_name(path));
  610. } else if (WWW_prefix) {
  611. HTSprintf0(&result, "%s%s%s", "/Net/", host, path);
  612. CTRACE((tfp, "Node `%s' means file `%s'\n", name, result));
  613. } else {
  614. StrAllocCopy(result, path);
  615. }
  616. } else if (WWW_prefix) { /* other access */
  617. #ifdef VMS
  618. if ((home = LYGetEnv("HOME")) == 0)
  619. home = HTCacheRoot;
  620. else
  621. home = HTVMS_wwwName(home);
  622. #else
  623. #if defined(_WINDOWS) /* 1997/10/16 (Thu) 20:42:51 */
  624. home = Home_Dir();
  625. #else
  626. home = LYGetEnv("HOME");
  627. #endif
  628. if (home == 0)
  629. home = "/tmp";
  630. #endif /* VMS */
  631. HTSprintf0(&result, "%s/WWW/%s/%s%s", home, acc_method, host, path);
  632. } else {
  633. StrAllocCopy(result, path);
  634. }
  635. FREE(host);
  636. FREE(path);
  637. FREE(acc_method);
  638. CTRACE((tfp, "HTnameOfFile_WWW(%s,%d,%d) = %s\n",
  639. name, WWW_prefix, expand_all, result));
  640. return result;
  641. }
  642. /* Make a WWW name from a full local path name.
  643. * --------------------------------------------
  644. *
  645. * Bugs:
  646. * At present, only the names of two network root nodes are hand-coded
  647. * in and valid for the NeXT only. This should be configurable in
  648. * the general case.
  649. */
  650. char *WWW_nameOfFile(const char *name)
  651. {
  652. char *result = NULL;
  653. #ifdef NeXT
  654. if (0 == strncmp("/private/Net/", name, 13)) {
  655. HTSprintf0(&result, "%s//%s", STR_FILE_URL, name + 13);
  656. } else
  657. #endif /* NeXT */
  658. if (0 == strncmp(HTMountRoot, name, 5)) {
  659. HTSprintf0(&result, "%s//%s", STR_FILE_URL, name + 5);
  660. } else {
  661. HTSprintf0(&result, "%s//%s%s", STR_FILE_URL, HTHostName(), name);
  662. }
  663. CTRACE((tfp, "File `%s'\n\tmeans node `%s'\n", name, result));
  664. return result;
  665. }
  666. /* Determine a suitable suffix, given the representation.
  667. * ------------------------------------------------------
  668. *
  669. * On entry,
  670. * rep is the atomized MIME style representation
  671. * enc is an encoding, trivial (8bit, binary, etc.) or gzip etc.
  672. *
  673. * On exit:
  674. * Returns a pointer to a suitable suffix string if one has been
  675. * found, else "".
  676. */
  677. const char *HTFileSuffix(HTAtom *rep,
  678. const char *enc)
  679. {
  680. HTSuffix *suff;
  681. #ifdef FNAMES_8_3
  682. HTSuffix *first_found = NULL;
  683. #endif
  684. BOOL trivial_enc;
  685. int n;
  686. int i;
  687. #define NO_INIT /* don't init anymore since I do it in Lynx at startup */
  688. #ifndef NO_INIT
  689. if (!HTSuffixes)
  690. HTFileInit();
  691. #endif /* !NO_INIT */
  692. trivial_enc = (BOOL) IsUnityEncStr(enc);
  693. n = HTList_count(HTSuffixes);
  694. for (i = 0; i < n; i++) {
  695. suff = (HTSuffix *) HTList_objectAt(HTSuffixes, i);
  696. if (suff->rep == rep &&
  697. #if defined(VMS) || defined(FNAMES_8_3)
  698. /* Don't return a suffix whose first char is a dot, and which
  699. has more dots or asterisks after that, for
  700. these systems - kw */
  701. (!suff->suffix || !suff->suffix[0] || suff->suffix[0] != '.' ||
  702. (strchr(suff->suffix + 1, '.') == NULL &&
  703. strchr(suff->suffix + 1, '*') == NULL)) &&
  704. #endif
  705. ((trivial_enc && IsUnityEnc(suff->encoding)) ||
  706. (!trivial_enc && !IsUnityEnc(suff->encoding) &&
  707. strcmp(enc, HTAtom_name(suff->encoding)) == 0))) {
  708. #ifdef FNAMES_8_3
  709. if (suff->suffix && (strlen(suff->suffix) <= 4)) {
  710. /*
  711. * If length of suffix (including dot) is 4 or smaller, return
  712. * this one even if we found a longer one earlier - kw
  713. */
  714. return suff->suffix;
  715. } else if (!first_found) {
  716. first_found = suff; /* remember this one */
  717. }
  718. #else
  719. return suff->suffix; /* OK -- found */
  720. #endif
  721. }
  722. }
  723. #ifdef FNAMES_8_3
  724. if (first_found)
  725. return first_found->suffix;
  726. #endif
  727. return ""; /* Dunno */
  728. }
  729. /*
  730. * Trim version from VMS filenames to avoid confusing comparisons.
  731. */
  732. #ifdef VMS
  733. static const char *VMS_trim_version(const char *filename)
  734. {
  735. const char *result = filename;
  736. const char *version = strchr(filename, ';');
  737. if (version != 0) {
  738. static char *stripped;
  739. StrAllocCopy(stripped, filename);
  740. stripped[version - filename] = '\0';
  741. result = (const char *) stripped;
  742. }
  743. return result;
  744. }
  745. #define VMS_DEL_VERSION(name) name = VMS_trim_version(name)
  746. #else
  747. #define VMS_DEL_VERSION(name) /* nothing */
  748. #endif
  749. /* Determine file format from file name.
  750. * -------------------------------------
  751. *
  752. * This version will return the representation and also set
  753. * a variable for the encoding.
  754. *
  755. * Encoding may be a unity encoding (binary, 8bit, etc.) or
  756. * a content-coding like gzip, compress.
  757. *
  758. * It will handle for example x.txt, x.txt,Z, x.Z
  759. */
  760. HTFormat HTFileFormat(const char *filename,
  761. HTAtom **pencoding,
  762. const char **pdesc)
  763. {
  764. HTSuffix *suff;
  765. int n;
  766. int i;
  767. int lf;
  768. VMS_DEL_VERSION(filename);
  769. if (pencoding)
  770. *pencoding = NULL;
  771. if (pdesc)
  772. *pdesc = NULL;
  773. if (LYforce_HTML_mode) {
  774. if (pencoding)
  775. *pencoding = WWW_ENC_8BIT;
  776. return WWW_HTML;
  777. }
  778. #ifndef NO_INIT
  779. if (!HTSuffixes)
  780. HTFileInit();
  781. #endif /* !NO_INIT */
  782. lf = strlen(filename);
  783. n = HTList_count(HTSuffixes);
  784. for (i = 0; i < n; i++) {
  785. int ls;
  786. suff = (HTSuffix *) HTList_objectAt(HTSuffixes, i);
  787. ls = strlen(suff->suffix);
  788. if ((ls <= lf) && 0 == strcasecomp(suff->suffix, filename + lf - ls)) {
  789. int j;
  790. if (pencoding)
  791. *pencoding = suff->encoding;
  792. if (pdesc)
  793. *pdesc = suff->desc;
  794. if (suff->rep) {
  795. return suff->rep; /* OK -- found */
  796. }
  797. for (j = 0; j < n; j++) { /* Got encoding, need representation */
  798. int ls2;
  799. suff = (HTSuffix *) HTList_objectAt(HTSuffixes, j);
  800. ls2 = strlen(suff->suffix);
  801. if ((ls + ls2 <= lf) &&
  802. !strncasecomp(suff->suffix,
  803. filename + lf - ls - ls2, ls2)) {
  804. if (suff->rep) {
  805. if (pdesc && !(*pdesc))
  806. *pdesc = suff->desc;
  807. if (pencoding && IsUnityEnc(*pencoding) &&
  808. *pencoding != WWW_ENC_7BIT &&
  809. !IsUnityEnc(suff->encoding))
  810. *pencoding = suff->encoding;
  811. return suff->rep;
  812. }
  813. }
  814. }
  815. }
  816. }
  817. /* defaults tree */
  818. suff = strchr(filename, '.') ? /* Unknown suffix */
  819. (unknown_suffix.rep ? &unknown_suffix : &no_suffix)
  820. : &no_suffix;
  821. /*
  822. * Set default encoding unless found with suffix already.
  823. */
  824. if (pencoding && !*pencoding) {
  825. *pencoding = (suff->encoding
  826. ? suff->encoding
  827. : HTAtom_for("binary"));
  828. }
  829. return suff->rep ? suff->rep : WWW_BINARY;
  830. }
  831. /* Revise the file format in relation to the Lynx charset. - FM
  832. * -------------------------------------------------------
  833. *
  834. * This checks the format associated with an anchor for
  835. * an extended MIME Content-Type, and if a charset is
  836. * indicated, sets Lynx up for proper handling in relation
  837. * to the currently selected character set. - FM
  838. */
  839. HTFormat HTCharsetFormat(HTFormat format,
  840. HTParentAnchor *anchor,
  841. int default_LYhndl)
  842. {
  843. char *cp = NULL, *cp1, *cp2, *cp3 = NULL, *cp4;
  844. BOOL chartrans_ok = FALSE;
  845. int chndl = -1;
  846. FREE(anchor->charset);
  847. StrAllocCopy(cp, format->name);
  848. LYLowerCase(cp);
  849. if (((cp1 = strchr(cp, ';')) != NULL) &&
  850. (cp2 = strstr(cp1, "charset")) != NULL) {
  851. CTRACE((tfp, "HTCharsetFormat: Extended MIME Content-Type is %s\n",
  852. format->name));
  853. cp2 += 7;
  854. while (*cp2 == ' ' || *cp2 == '=')
  855. cp2++;
  856. StrAllocCopy(cp3, cp2); /* copy to mutilate more */
  857. for (cp4 = cp3; (*cp4 != '\0' && *cp4 != '"' &&
  858. *cp4 != ';' && *cp4 != ':' &&
  859. !WHITE(*cp4)); cp4++) {
  860. ; /* do nothing */
  861. }
  862. *cp4 = '\0';
  863. cp4 = cp3;
  864. chndl = UCGetLYhndl_byMIME(cp3);
  865. if (UCCanTranslateFromTo(chndl, current_char_set)) {
  866. chartrans_ok = YES;
  867. *cp1 = '\0';
  868. format = HTAtom_for(cp);
  869. StrAllocCopy(anchor->charset, cp4);
  870. HTAnchor_setUCInfoStage(anchor, chndl,
  871. UCT_STAGE_MIME,
  872. UCT_SETBY_MIME);
  873. } else if (chndl < 0) {
  874. /*
  875. * Got something but we don't recognize it.
  876. */
  877. chndl = UCLYhndl_for_unrec;
  878. if (chndl < 0)
  879. /*
  880. * UCLYhndl_for_unrec not defined :-( fallback to
  881. * UCLYhndl_for_unspec which always valid.
  882. */
  883. chndl = UCLYhndl_for_unspec; /* always >= 0 */
  884. if (UCCanTranslateFromTo(chndl, current_char_set)) {
  885. chartrans_ok = YES;
  886. HTAnchor_setUCInfoStage(anchor, chndl,
  887. UCT_STAGE_MIME,
  888. UCT_SETBY_DEFAULT);
  889. }
  890. }
  891. if (chartrans_ok) {
  892. LYUCcharset *p_in = HTAnchor_getUCInfoStage(anchor,
  893. UCT_STAGE_MIME);
  894. LYUCcharset *p_out = HTAnchor_setUCInfoStage(anchor,
  895. current_char_set,
  896. UCT_STAGE_HTEXT,
  897. UCT_SETBY_DEFAULT);
  898. if (!p_out) {
  899. /*
  900. * Try again.
  901. */
  902. p_out = HTAnchor_getUCInfoStage(anchor, UCT_STAGE_HTEXT);
  903. }
  904. if (!strcmp(p_in->MIMEname, "x-transparent")) {
  905. HTPassEightBitRaw = TRUE;
  906. HTAnchor_setUCInfoStage(anchor,
  907. HTAnchor_getUCLYhndl(anchor,
  908. UCT_STAGE_HTEXT),
  909. UCT_STAGE_MIME,
  910. UCT_SETBY_DEFAULT);
  911. }
  912. if (!strcmp(p_out->MIMEname, "x-transparent")) {
  913. HTPassEightBitRaw = TRUE;
  914. HTAnchor_setUCInfoStage(anchor,
  915. HTAnchor_getUCLYhndl(anchor,
  916. UCT_STAGE_MIME),
  917. UCT_STAGE_HTEXT,
  918. UCT_SETBY_DEFAULT);
  919. }
  920. if (p_in->enc != UCT_ENC_CJK) {
  921. HTCJK = NOCJK;
  922. if (!(p_in->codepoints &
  923. UCT_CP_SUBSETOF_LAT1) &&
  924. chndl == current_char_set) {
  925. HTPassEightBitRaw = TRUE;
  926. }
  927. } else if (p_out->enc == UCT_ENC_CJK) {
  928. Set_HTCJK(p_in->MIMEname, p_out->MIMEname);
  929. }
  930. } else {
  931. /*
  932. * Cannot translate. If according to some heuristic the given
  933. * charset and the current display character both are likely to be
  934. * like ISO-8859 in structure, pretend we have some kind of match.
  935. */
  936. BOOL given_is_8859 = (BOOL) (!strncmp(cp4, "iso-8859-", 9) &&
  937. isdigit(UCH(cp4[9])));
  938. BOOL given_is_8859like = (BOOL) (given_is_8859 ||
  939. !strncmp(cp4, "windows-", 8) ||
  940. !strncmp(cp4, "cp12", 4) ||
  941. !strncmp(cp4, "cp-12", 5));
  942. BOOL given_and_display_8859like = (BOOL) (given_is_8859like &&
  943. (strstr(LYchar_set_names[current_char_set],
  944. "ISO-8859") ||
  945. strstr(LYchar_set_names[current_char_set],
  946. "windows-")));
  947. if (given_and_display_8859like) {
  948. *cp1 = '\0';
  949. format = HTAtom_for(cp);
  950. }
  951. if (given_is_8859) {
  952. cp1 = &cp4[10];
  953. while (*cp1 &&
  954. isdigit(UCH(*cp1)))
  955. cp1++;
  956. *cp1 = '\0';
  957. }
  958. if (given_and_display_8859like) {
  959. StrAllocCopy(anchor->charset, cp4);
  960. HTPassEightBitRaw = TRUE;
  961. }
  962. HTAlert(*cp4 ? cp4 : anchor->charset);
  963. }
  964. FREE(cp3);
  965. } else if (cp1 != NULL) {
  966. /*
  967. * No charset parameter is present. Ignore all other parameters, as we
  968. * do when charset is present. - FM
  969. */
  970. *cp1 = '\0';
  971. format = HTAtom_for(cp);
  972. }
  973. FREE(cp);
  974. /*
  975. * Set up defaults, if needed. - FM
  976. */
  977. if (!chartrans_ok && !anchor->charset && default_LYhndl >= 0) {
  978. HTAnchor_setUCInfoStage(anchor, default_LYhndl,
  979. UCT_STAGE_MIME,
  980. UCT_SETBY_DEFAULT);
  981. }
  982. HTAnchor_copyUCInfoStage(anchor,
  983. UCT_STAGE_PARSER,
  984. UCT_STAGE_MIME,
  985. -1);
  986. return format;
  987. }
  988. /* Get various pieces of meta info from file name.
  989. * -----------------------------------------------
  990. *
  991. * LYGetFileInfo fills in information that can be determined without
  992. * an actual (new) access to the filesystem, based on current suffix
  993. * and character set configuration. If the file has been loaded and
  994. * parsed before (with the same URL generated here!) and the anchor
  995. * is still around, some results may be influenced by that (in
  996. * particular, charset info from a META tag - this is not actually
  997. * tested!).
  998. * The caller should not keep pointers to the returned objects around
  999. * for too long, the valid lifetimes vary. In particular, the returned
  1000. * charset string should be copied if necessary. If return of the
  1001. * file_anchor is requested, that one can be used to retrieve
  1002. * additional bits of info that are stored in the anchor object and
  1003. * are not covered here; as usual, don't keep pointers to the
  1004. * file_anchor longer than necessary since the object may disappear
  1005. * through HTuncache_current_document or at the next document load.
  1006. * - kw
  1007. */
  1008. void LYGetFileInfo(const char *filename,
  1009. HTParentAnchor **pfile_anchor,
  1010. HTFormat *pformat,
  1011. HTAtom **pencoding,
  1012. const char **pdesc,
  1013. const char **pcharset,
  1014. int *pfile_cs)
  1015. {
  1016. char *Afn;
  1017. char *Aname = NULL;
  1018. HTFormat format;
  1019. HTAtom *myEnc = NULL;
  1020. HTParentAnchor *file_anchor;
  1021. const char *file_csname;
  1022. int file_cs;
  1023. /*
  1024. * Convert filename to URL. Note that it is always supposed to be a
  1025. * filename, not maybe-filename-maybe-URL, so we don't use
  1026. * LYFillLocalFileURL and LYEnsureAbsoluteURL. - kw
  1027. */
  1028. Afn = HTEscape(filename, URL_PATH);
  1029. LYLocalFileToURL(&Aname, Afn);
  1030. file_anchor = HTAnchor_findSimpleAddress(Aname);
  1031. file_csname = file_anchor->charset;
  1032. format = HTFileFormat(filename, &myEnc, pdesc);
  1033. format = HTCharsetFormat(format, file_anchor, UCLYhndl_HTFile_for_unspec);
  1034. file_cs = HTAnchor_getUCLYhndl(file_anchor, UCT_STAGE_MIME);
  1035. if (!file_csname) {
  1036. if (file_cs >= 0)
  1037. file_csname = LYCharSet_UC[file_cs].MIMEname;
  1038. else
  1039. file_csname = "display character set";
  1040. }
  1041. CTRACE((tfp, "GetFileInfo: '%s' is a%s %s %s file, charset=%s (%d).\n",
  1042. filename,
  1043. ((myEnc && *HTAtom_name(myEnc) == '8') ? "n" : myEnc ? "" :
  1044. *HTAtom_name(format) == 'a' ? "n" : ""),
  1045. myEnc ? HTAtom_name(myEnc) : "",
  1046. HTAtom_name(format),
  1047. file_csname,
  1048. file_cs));
  1049. FREE(Afn);
  1050. FREE(Aname);
  1051. if (pfile_anchor)
  1052. *pfile_anchor = file_anchor;
  1053. if (pformat)
  1054. *pformat = format;
  1055. if (pencoding)
  1056. *pencoding = myEnc;
  1057. if (pcharset)
  1058. *pcharset = file_csname;
  1059. if (pfile_cs)
  1060. *pfile_cs = file_cs;
  1061. }
  1062. /* Determine value from file name.
  1063. * -------------------------------
  1064. *
  1065. */
  1066. float HTFileValue(const char *filename)
  1067. {
  1068. HTSuffix *suff;
  1069. int n;
  1070. int i;
  1071. int lf = strlen(filename);
  1072. #ifndef NO_INIT
  1073. if (!HTSuffixes)
  1074. HTFileInit();
  1075. #endif /* !NO_INIT */
  1076. n = HTList_count(HTSuffixes);
  1077. for (i = 0; i < n; i++) {
  1078. int ls;
  1079. suff = (HTSuffix *) HTList_objectAt(HTSuffixes, i);
  1080. ls = strlen(suff->suffix);
  1081. if ((ls <= lf) && 0 == strcmp(suff->suffix, filename + lf - ls)) {
  1082. CTRACE((tfp, "File: Value of %s is %.3f\n",
  1083. filename, suff->quality));
  1084. return suff->quality; /* OK -- found */
  1085. }
  1086. }
  1087. return (float) 0.3; /* Dunno! */
  1088. }
  1089. /*
  1090. * Determine compression type from file name, by looking at its suffix.
  1091. * Sets as side-effect a pointer to the "dot" that begins the suffix.
  1092. */
  1093. CompressFileType HTCompressFileType(const char *filename,
  1094. const char *dots,
  1095. int *rootlen)
  1096. {
  1097. CompressFileType result = cftNone;
  1098. size_t len = strlen(filename);
  1099. const char *ftype = filename + len;
  1100. VMS_DEL_VERSION(filename);
  1101. if ((len > 4)
  1102. && !strcasecomp((ftype - 3), "bz2")
  1103. && strchr(dots, ftype[-4]) != 0) {
  1104. result = cftBzip2;
  1105. ftype -= 4;
  1106. } else if ((len > 3)
  1107. && !strcasecomp((ftype - 2), "gz")
  1108. && strchr(dots, ftype[-3]) != 0) {
  1109. result = cftGzip;
  1110. ftype -= 3;
  1111. } else if ((len > 3)
  1112. && !strcasecomp((ftype - 2), "zz")
  1113. && strchr(dots, ftype[-3]) != 0) {
  1114. result = cftDeflate;
  1115. ftype -= 3;
  1116. } else if ((len > 2)
  1117. && !strcmp((ftype - 1), "Z")
  1118. && strchr(dots, ftype[-2]) != 0) {
  1119. result = cftCompress;
  1120. ftype -= 2;
  1121. }
  1122. *rootlen = (ftype - filename);
  1123. CTRACE((tfp, "HTCompressFileType(%s) returns %d:%s\n",
  1124. filename, (int) result, filename + *rootlen));
  1125. return result;
  1126. }
  1127. /*
  1128. * Check if the token from "Content-Encoding" corresponds to a compression
  1129. * type. RFC 2068 (and cut/paste into RFC 2616) lists these:
  1130. * gzip
  1131. * compress
  1132. * deflate
  1133. * as well as "identity" (but that does nothing).
  1134. */
  1135. CompressFileType HTEncodingToCompressType(const char *coding)
  1136. {
  1137. CompressFileType result = cftNone;
  1138. if (coding == 0) {
  1139. result = cftNone;
  1140. } else if (!strcasecomp(coding, "gzip") ||
  1141. !strcasecomp(coding, "x-gzip")) {
  1142. result = cftGzip;
  1143. } else if (!strcasecomp(coding, "compress") ||
  1144. !strcasecomp(coding, "x-compress")) {
  1145. result = cftCompress;
  1146. } else if (!strcasecomp(coding, "bzip2") ||
  1147. !strcasecomp(coding, "x-bzip2")) {
  1148. result = cftBzip2;
  1149. } else if (!strcasecomp(coding, "deflate") ||
  1150. !strcasecomp(coding, "x-deflate")) {
  1151. result = cftDeflate;
  1152. }
  1153. return result;
  1154. }
  1155. /* Determine write access to a file.
  1156. * ---------------------------------
  1157. *
  1158. * On exit:
  1159. * Returns YES if file can be accessed and can be written to.
  1160. *
  1161. * Bugs:
  1162. * 1. No code for non-unix systems.
  1163. * 2. Isn't there a quicker way?
  1164. */
  1165. BOOL HTEditable(const char *filename)
  1166. {
  1167. #ifndef NO_GROUPS
  1168. GETGROUPS_T groups[NGROUPS];
  1169. uid_t myUid;
  1170. int ngroups; /* The number of groups */
  1171. struct stat fileStatus;
  1172. int i;
  1173. if (stat(filename, &fileStatus)) /* Get details of filename */
  1174. return NO; /* Can't even access file! */
  1175. ngroups = getgroups(NGROUPS, groups); /* Groups to which I belong */
  1176. myUid = geteuid(); /* Get my user identifier */
  1177. if (TRACE) {
  1178. int i2;
  1179. fprintf(tfp,
  1180. "File mode is 0%o, uid=%d, gid=%d. My uid=%d, %d groups (",
  1181. (unsigned int) fileStatus.st_mode,
  1182. (int) fileStatus.st_uid,
  1183. (int) fileStatus.st_gid,
  1184. (int) myUid,
  1185. (int) ngroups);
  1186. for (i2 = 0; i2 < ngroups; i2++)
  1187. fprintf(tfp, " %d", (int) groups[i2]);
  1188. fprintf(tfp, ")\n");
  1189. }
  1190. if (fileStatus.st_mode & 0002) /* I can write anyway? */
  1191. return YES;
  1192. if ((fileStatus.st_mode & 0200) /* I can write my own file? */
  1193. &&(fileStatus.st_uid == myUid))
  1194. return YES;
  1195. if (fileStatus.st_mode & 0020) /* Group I am in can write? */
  1196. {
  1197. for (i = 0; i < ngroups; i++) {
  1198. if (groups[i] == fileStatus.st_gid)
  1199. return YES;
  1200. }
  1201. }
  1202. CTRACE((tfp, "\tFile is not editable.\n"));
  1203. #endif /* NO_GROUPS */
  1204. return NO; /* If no excuse, can't do */
  1205. }
  1206. /* Make a save stream.
  1207. * -------------------
  1208. *
  1209. * The stream must be used for writing back the file.
  1210. * @@@ no backup done
  1211. */
  1212. HTStream *HTFileSaveStream(HTParentAnchor *anchor)
  1213. {
  1214. const char *addr = anchor->address;
  1215. char *localname = HTLocalName(addr);
  1216. FILE *fp = fopen(localname, BIN_W);
  1217. FREE(localname);
  1218. if (!fp)
  1219. return NULL;
  1220. return HTFWriter_new(fp);
  1221. }
  1222. /* Output one directory entry.
  1223. * ---------------------------
  1224. */
  1225. void HTDirEntry(HTStructured * target, const char *tail,
  1226. const char *entry)
  1227. {
  1228. char *relative = NULL;
  1229. char *stripped = NULL;
  1230. char *escaped = NULL;
  1231. int len;
  1232. StrAllocCopy(escaped, entry);
  1233. LYTrimPathSep(escaped);
  1234. if (strcmp(escaped, "..") != 0) {
  1235. stripped = escaped;
  1236. escaped = HTEscape(stripped, URL_XPALPHAS);
  1237. if (((len = strlen(escaped)) > 2) &&
  1238. escaped[(len - 3)] == '%' &&
  1239. escaped[(len - 2)] == '2' &&
  1240. TOUPPER(escaped[(len - 1)]) == 'F') {
  1241. escaped[(len - 3)] = '\0';
  1242. }
  1243. }
  1244. if (isEmpty(tail)) {
  1245. /*
  1246. * Handle extra slash at end of path.
  1247. */
  1248. HTStartAnchor(target, NULL, (escaped[0] != '\0' ? escaped : "/"));
  1249. } else {
  1250. /*
  1251. * If empty tail, gives absolute ref below.
  1252. */
  1253. relative = 0;
  1254. HTSprintf0(&relative, "%s%s%s",
  1255. tail,
  1256. (*escaped != '\0' ? "/" : ""),
  1257. escaped);
  1258. HTStartAnchor(target, NULL, relative);
  1259. FREE(relative);
  1260. }
  1261. FREE(stripped);
  1262. FREE(escaped);
  1263. }
  1264. static BOOL view_structured(HTFormat format_out)
  1265. {
  1266. BOOL result = FALSE;
  1267. #ifdef USE_PRETTYSRC
  1268. if (psrc_view
  1269. || (format_out == HTAtom_for("www/dump")))
  1270. result = TRUE;
  1271. #else
  1272. if (format_out == WWW_SOURCE)
  1273. result = TRUE;
  1274. #endif
  1275. return result;
  1276. }
  1277. /*
  1278. * Write a DOCTYPE to the given stream if we happen to want to see the
  1279. * source view, or are dumping source. This is not needed when the source
  1280. * is not visible, since the document is rendered from a HTStructured object.
  1281. */
  1282. void HTStructured_doctype(HTStructured * target, HTFormat format_out)
  1283. {
  1284. if (view_structured(format_out))
  1285. PUTS("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
  1286. }
  1287. void HTStructured_meta(HTStructured * target, HTFormat format_out)
  1288. {
  1289. if (view_structured(format_out))
  1290. PUTS("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">\n");
  1291. }
  1292. /* Output parent directory entry.
  1293. * ------------------------------
  1294. *
  1295. * This gives the TITLE and H1 header, and also a link
  1296. * to the parent directory if appropriate.
  1297. *
  1298. * On exit:
  1299. * Returns TRUE if an "Up to <parent>" link was not created
  1300. * for a readable local directory because LONG_LIST is defined
  1301. * and NO_PARENT_DIR_REFERENCE is not defined, so that the
  1302. * calling function should use LYListFmtParse() to create a link
  1303. * to the parent directory. Otherwise, it returns FALSE. - FM
  1304. */
  1305. BOOL HTDirTitles(HTStructured * target, HTParentAnchor *anchor,
  1306. HTFormat format_out,
  1307. BOOL tildeIsTop)
  1308. {
  1309. const char *logical = anchor->address;
  1310. char *path = HTParse(logical, "", PARSE_PATH + PARSE_PUNCTUATION);
  1311. char *current;
  1312. char *cp = NULL;
  1313. BOOL need_parent_link = FALSE;
  1314. int i;
  1315. #if defined(USE_DOS_DRIVES)
  1316. BOOL local_link = (strlen(logical) > 18
  1317. && !strncasecomp(logical, "file://localhost/", 17)
  1318. && LYIsDosDrive(logical + 17));
  1319. BOOL is_remote = !local_link;
  1320. #else
  1321. #define is_remote TRUE
  1322. #endif
  1323. /*
  1324. * Check tildeIsTop for treating home directory as Welcome (assume the
  1325. * tilde is not followed by a username). - FM
  1326. */
  1327. if (tildeIsTop && !strncmp(path, "/~", 2)) {
  1328. if (path[2] == '\0') {
  1329. path[1] = '\0';
  1330. } else {
  1331. for (i = 0; path[(i + 2)]; i++) {
  1332. path[i] = path[(i + 2)];
  1333. }
  1334. path[i] = '\0';
  1335. }
  1336. }
  1337. /*
  1338. * Trim out the ;type= parameter, if present. - FM
  1339. */
  1340. if ((cp = strrchr(path, ';')) != NULL) {
  1341. if (!strncasecomp((cp + 1), "type=", 5)) {
  1342. if (TOUPPER(*(cp + 6)) == 'D' ||
  1343. TOUPPER(*(cp + 6)) == 'A' ||
  1344. TOUPPER(*(cp + 6)) == 'I')
  1345. *cp = '\0';
  1346. }
  1347. cp = NULL;
  1348. }
  1349. current = LYPathLeaf(path); /* last part or "" */
  1350. {
  1351. char *printable = NULL;
  1352. #ifdef DIRED_SUPPORT
  1353. printable = HTURLPath_toFile(((!strncasecomp(path, "/%2F", 4)) /* "//" ? */
  1354. ? (path + 1)
  1355. : path),
  1356. TRUE,
  1357. is_remote);
  1358. if (0 == strncasecomp(printable, "/vmsysu:", 8) ||
  1359. 0 == strncasecomp(printable, "/anonymou.", 10)) {
  1360. StrAllocCopy(cp, (printable + 1));
  1361. StrAllocCopy(printable, cp);
  1362. FREE(cp);
  1363. }
  1364. #else
  1365. StrAllocCopy(printable, current);
  1366. HTUnEscape(printable);
  1367. #endif /* DIRED_SUPPORT */
  1368. HTStructured_doctype(target, format_out);
  1369. START(HTML_HEAD);
  1370. PUTC('\n');
  1371. START(HTML_TITLE);
  1372. PUTS(*printable ? printable : WELCOME_MSG);
  1373. PUTS(SEGMENT_DIRECTORY);
  1374. END(HTML_TITLE);
  1375. PUTC('\n');
  1376. HTStructured_meta(target, format_out);
  1377. END(HTML_HEAD);
  1378. PUTC('\n');
  1379. START(HTML_BODY);
  1380. PUTC('\n');
  1381. #ifdef DIRED_SUPPORT
  1382. START(HTML_H2);
  1383. PUTS(*printable ? SEGMENT_CURRENT_DIR : "");
  1384. PUTS(*printable ? printable : WELCOME_MSG);
  1385. END(HTML_H2);
  1386. PUTC('\n');
  1387. #else
  1388. START(HTML_H1);
  1389. PUTS(*printable ? printable : WELCOME_MSG);
  1390. END(HTML_H1);
  1391. PUTC('\n');
  1392. #endif /* DIRED_SUPPORT */
  1393. if (((0 == strncasecomp(printable, "vmsysu:", 7)) &&
  1394. (cp = strchr(printable, '.')) != NULL &&
  1395. strchr(cp, '/') == NULL) ||
  1396. (0 == strncasecomp(printable, "anonymou.", 9) &&
  1397. strchr(printable, '/') == NULL)) {
  1398. FREE(printable);
  1399. FREE(path);
  1400. return (need_parent_link);
  1401. }
  1402. FREE(printable);
  1403. }
  1404. #ifndef NO_PARENT_DIR_REFERENCE
  1405. /*
  1406. * Make link back to parent directory.
  1407. */
  1408. if (current - path > 0
  1409. && LYIsPathSep(current[-1])
  1410. && current[0] != '\0') { /* was a slash AND something else too */
  1411. char *parent = NULL;
  1412. char *relative = NULL;
  1413. current[-1] = '\0';
  1414. parent = strrchr(path, '/'); /* penultimate slash */
  1415. if ((parent &&
  1416. (!strcmp(parent, "/..") ||
  1417. !strncasecomp(parent, "/%2F", 4))) ||
  1418. !strncasecomp(current, "%2F", 3)) {
  1419. FREE(path);
  1420. return (need_parent_link);
  1421. }
  1422. relative = 0;
  1423. HTSprintf0(&relative, "%s/..", current);
  1424. #if defined(DOSPATH) || defined(__EMX__)
  1425. if (local_link) {
  1426. if (parent != 0 && strlen(parent) == 3) {
  1427. StrAllocCat(relative, "/.");
  1428. }
  1429. } else
  1430. #endif
  1431. #if !defined (VMS)
  1432. {
  1433. /*
  1434. * On Unix, if it's not ftp and the directory cannot be read, don't
  1435. * put out a link.
  1436. *
  1437. * On VMS, this problem is dealt with internally by
  1438. * HTVMSBrowseDir().
  1439. */
  1440. DIR *dp = NULL;
  1441. if (LYisLocalFile(logical)) {
  1442. /*
  1443. * We need an absolute file path for the opendir. We also need
  1444. * to unescape for this test. Don't worry about %2F now, they
  1445. * presumably have been dealt with above, and shouldn't appear
  1446. * for local files anyway... Assume OS / filesystem will just
  1447. * ignore superfluous slashes. - KW
  1448. */
  1449. char *fullparentpath = NULL;
  1450. /*
  1451. * Path has been shortened above.
  1452. */
  1453. StrAllocCopy(fullparentpath, *path ? path : "/");
  1454. /*
  1455. * Guard against weirdness.
  1456. */
  1457. if (0 == strcmp(current, "..")) {
  1458. StrAllocCat(fullparentpath, "/../..");
  1459. } else if (0 == strcmp(current, ".")) {
  1460. StrAllocCat(fullparentpath, "/..");
  1461. }
  1462. HTUnEscape(fullparentpath);
  1463. if ((dp = opendir(fullparentpath)) == NULL) {
  1464. FREE(fullparentpath);
  1465. FREE(relative);
  1466. FREE(path);
  1467. return (need_parent_link);
  1468. }
  1469. closedir(dp);
  1470. FREE(fullparentpath);
  1471. #ifdef LONG_LIST
  1472. need_parent_link = TRUE;
  1473. FREE(path);
  1474. FREE(relative);
  1475. return (need_parent_link);
  1476. #endif /* LONG_LIST */
  1477. }
  1478. }
  1479. #endif /* !VMS */
  1480. HTStartAnchor(target, "", relative);
  1481. FREE(relative);
  1482. PUTS(SEGMENT_UP_TO);
  1483. if (parent) {
  1484. if ((0 == strcmp(current, ".")) ||
  1485. (0 == strcmp(current, ".."))) {
  1486. /*
  1487. * Should not happen, but if it does, at least avoid giving
  1488. * misleading info. - KW
  1489. */
  1490. PUTS("..");
  1491. } else {
  1492. char *printable = NULL;
  1493. StrAllocCopy(printable, parent + 1);
  1494. HTUnEscape(printable);
  1495. PUTS(printable);
  1496. FREE(printable);
  1497. }
  1498. } else {
  1499. PUTC('/');
  1500. }
  1501. END(HTML_A);
  1502. PUTC('\n');
  1503. }
  1504. #endif /* !NO_PARENT_DIR_REFERENCE */
  1505. FREE(path);
  1506. return (need_parent_link);
  1507. }
  1508. #if defined HAVE_READDIR
  1509. /* Send README file.
  1510. * -----------------
  1511. *
  1512. * If a README file exists, then it is inserted into the document here.
  1513. */
  1514. static void do_readme(HTStructured * target, const char *localname)
  1515. {
  1516. FILE *fp;
  1517. char *readme_file_name = NULL;
  1518. int ch;
  1519. HTSprintf0(&readme_file_name, "%s/%s", localname, HT_DIR_README_FILE);
  1520. fp = fopen(readme_file_name, "r");
  1521. if (fp) {
  1522. HTStructuredClass targetClass;
  1523. targetClass = *target->isa; /* (Can't init agregate in K&R) */
  1524. START(HTML_PRE);
  1525. while ((ch = fgetc(fp)) != EOF) {
  1526. PUTC((char) ch);
  1527. }
  1528. END(HTML_PRE);
  1529. HTDisplayPartial();
  1530. fclose(fp);
  1531. }
  1532. FREE(readme_file_name);
  1533. }
  1534. #define DIRED_BLOK(obj) (((DIRED *)(obj))->sort_tags)
  1535. #define DIRED_NAME(obj) (((DIRED *)(obj))->file_name)
  1536. #define NM_cmp(a,b) ((a) < (b) ? -1 : ((a) > (b) ? 1 : 0))
  1537. #if defined(LONG_LIST) && defined(DIRED_SUPPORT)
  1538. static const char *file_type(const char *path)
  1539. {
  1540. const char *type;
  1541. while (*path == '.')
  1542. ++path;
  1543. type = strchr(path, '.');
  1544. if (type == NULL)
  1545. type = "";
  1546. return type;
  1547. }
  1548. #endif /* LONG_LIST && DIRED_SUPPORT */
  1549. static int dired_cmp(void *a, void *b)
  1550. {
  1551. DIRED *p = (DIRED *) a;
  1552. DIRED *q = (DIRED *) b;
  1553. int code = p->sort_tags - q->sort_tags;
  1554. #if defined(LONG_LIST) && defined(DIRED_SUPPORT)
  1555. if (code == 0) {
  1556. switch (dir_list_order) {
  1557. case ORDER_BY_SIZE:
  1558. code = -NM_cmp(p->file_info.st_size, q->file_info.st_size);
  1559. break;
  1560. case ORDER_BY_DATE:
  1561. code = -NM_cmp(p->file_info.st_mtime, q->file_info.st_mtime);
  1562. break;
  1563. case ORDER_BY_MODE:
  1564. code = NM_cmp(p->file_info.st_mode, q->file_info.st_mode);
  1565. break;
  1566. case ORDER_BY_USER:
  1567. code = NM_cmp(p->file_info.st_uid, q->file_info.st_uid);
  1568. break;
  1569. case ORDER_BY_GROUP:
  1570. code = NM_cmp(p->file_info.st_gid, q->file_info.st_gid);
  1571. break;
  1572. case ORDER_BY_TYPE:
  1573. code = AS_cmp(file_type(p->file_name), file_type(q->file_name));
  1574. break;
  1575. default:
  1576. code = 0;
  1577. break;
  1578. }
  1579. }
  1580. #endif /* LONG_LIST && DIRED_SUPPORT */
  1581. if (code == 0)
  1582. code = AS_cmp(p->file_name, q->file_name);
  1583. #if 0
  1584. CTRACE((tfp, "dired_cmp(%d) ->%d\n\t%c:%s (%s)\n\t%c:%s (%s)\n",
  1585. dir_list_order,
  1586. code,
  1587. p->sort_tags, p->file_name, file_type(p->file_name),
  1588. q->sort_tags, q->file_name, file_type(q->file_name)));
  1589. #endif
  1590. return code;
  1591. }
  1592. static int print_local_dir(DIR *dp, char *localname,
  1593. HTParentAnchor *anchor,
  1594. HTFormat format_out,
  1595. HTStream *sink)
  1596. {
  1597. HTStructured *target; /* HTML object */
  1598. HTBTree *bt;
  1599. HTStructuredClass targetClass;
  1600. STRUCT_DIRENT *dirbuf;
  1601. char *pathname = NULL;
  1602. char *tail = NULL;
  1603. char *p;
  1604. BOOL present[HTML_A_ATTRIBUTES];
  1605. char *tmpfilename = NULL;
  1606. BOOL need_parent_link = FALSE;
  1607. BOOL preformatted = FALSE;
  1608. int status;
  1609. int i;
  1610. struct stat *actual_info;
  1611. #ifdef DISP_PARTIAL
  1612. int num_of_entries = 0; /* lines counter */
  1613. #endif
  1614. #ifdef S_IFLNK
  1615. struct stat link_info;
  1616. #endif
  1617. CTRACE((tfp, "print_local_dir() started\n"));
  1618. pathname = HTParse(anchor->address, "",
  1619. PARSE_PATH + PARSE_PUNCTUATION);
  1620. if ((p = strrchr(pathname, '/')) == 0)
  1621. p = "/";
  1622. StrAllocCopy(tail, (p + 1));
  1623. FREE(pathname);
  1624. if (UCLYhndl_HTFile_for_unspec >= 0) {
  1625. HTAnchor_setUCInfoStage(anchor,
  1626. UCLYhndl_HTFile_for_unspec,
  1627. UCT_STAGE_PARSER,
  1628. UCT_SETBY_DEFAULT);
  1629. }
  1630. target = HTML_new(anchor, format_out, sink);
  1631. targetClass = *target->isa; /* Copy routine entry points */
  1632. for (i = 0; i < HTML_A_ATTRIBUTES; i++)
  1633. present[i] = (BOOL) (i == HTML_A_HREF);
  1634. /*
  1635. * The need_parent_link flag will be set if an "Up to <parent>" link was
  1636. * not created for a readable parent in HTDirTitles() because LONG_LIST is
  1637. * defined and NO_PARENT_DIR_REFERENCE is not defined so that need we to
  1638. * create the link via an LYListFmtParse() call. - FM
  1639. */
  1640. need_parent_link = HTDirTitles(target, anchor, format_out, FALSE);
  1641. #ifdef DIRED_SUPPORT
  1642. if (!isLYNXCGI(anchor->address)) {
  1643. HTAnchor_setFormat(anchor, WWW_DIRED);
  1644. lynx_edit_mode = TRUE;
  1645. }
  1646. #endif /* DIRED_SUPPORT */
  1647. if (HTDirReadme == HT_DIR_README_TOP)
  1648. do_readme(target, localname);
  1649. bt = HTBTree_new(dired_cmp);
  1650. _HTProgress(READING_DIRECTORY);
  1651. status = HT_LOADED; /* assume we don't get interrupted */
  1652. while ((dirbuf = readdir(dp)) != NULL) {
  1653. /*
  1654. * While there are directory entries to be read...
  1655. */
  1656. DIRED *data = NULL;
  1657. #ifdef STRUCT_DIRENT__D_INO
  1658. if (dirbuf->d_ino == 0)
  1659. /*
  1660. * If the entry is not being used, skip it.
  1661. */
  1662. continue;
  1663. #endif
  1664. /*
  1665. * Skip self, parent if handled in HTDirTitles() or if
  1666. * NO_PARENT_DIR_REFERENCE is not defined, and any dot files if
  1667. * no_dotfiles is set or show_dotfiles is not set. - FM
  1668. */
  1669. if (!strcmp(dirbuf->d_name, ".") /* self */ ||
  1670. (!strcmp(dirbuf->d_name, "..") /* parent */ &&
  1671. need_parent_link == FALSE) ||
  1672. ((strcmp(dirbuf->d_name, "..")) &&
  1673. (dirbuf->d_name[0] == '.' &&
  1674. (no_dotfiles || !show_dotfiles))))
  1675. continue;
  1676. StrAllocCopy(tmpfilename, localname);
  1677. /*
  1678. * If filename is not root directory, add trailing separator.
  1679. */
  1680. LYAddPathSep(&tmpfilename);
  1681. StrAllocCat(tmpfilename, dirbuf->d_name);
  1682. data = (DIRED *) malloc(sizeof(DIRED) + strlen(dirbuf->d_name) + 4);
  1683. if (data == NULL) {
  1684. status = HT_PARTIAL_CONTENT;
  1685. break;
  1686. }
  1687. LYTrimPathSep(tmpfilename);
  1688. actual_info = &(data->file_info);
  1689. #ifdef S_IFLNK
  1690. if (lstat(tmpfilename, actual_info) < 0) {
  1691. actual_info->st_mode = 0;
  1692. } else {
  1693. if (S_ISLNK(actual_info->st_mode)) {
  1694. actual_info = &link_info;
  1695. if (stat(tmpfilename, actual_info) < 0)
  1696. actual_info->st_mode = 0;
  1697. }
  1698. }
  1699. #else
  1700. if (stat(tmpfilename, actual_info) < 0)
  1701. actual_info->st_mode = 0;
  1702. #endif
  1703. strcpy(data->file_name, dirbuf->d_name);
  1704. #ifndef DIRED_SUPPORT
  1705. if (S_ISDIR(actual_info->st_mode)) {
  1706. data->sort_tags = 'D';
  1707. } else {
  1708. data->sort_tags = 'F';
  1709. /* D & F to have first directories, then files */
  1710. }
  1711. #else
  1712. if (S_ISDIR(actual_info->st_mode)) {
  1713. if (dir_list_style == MIXED_STYLE) {
  1714. data->sort_tags = ' ';
  1715. LYAddPathSep0(data->file_name);
  1716. } else if (!strcmp(dirbuf->d_name, "..")) {
  1717. data->sort_tags = 'A';
  1718. } else {
  1719. data->sort_tags = 'D';
  1720. }
  1721. } else if (dir_list_style == MIXED_STYLE) {
  1722. data->sort_tags = ' ';
  1723. } else if (dir_list_style == FILES_FIRST) {
  1724. data->sort_tags = 'C';
  1725. /* C & D to have first files, then directories */
  1726. } else {
  1727. data->sort_tags = 'F';
  1728. }
  1729. #endif /* !DIRED_SUPPORT */
  1730. /*
  1731. * Sort dirname in the tree bt.
  1732. */
  1733. HTBTree_add(bt, data);
  1734. #ifdef DISP_PARTIAL
  1735. /* optimize for expensive operation: */
  1736. if (num_of_entries % (partial_threshold > 0 ?
  1737. partial_threshold : display_lines)
  1738. == 0) {
  1739. if (HTCheckForInterrupt()) {
  1740. status = HT_PARTIAL_CONTENT;
  1741. break;
  1742. }
  1743. }
  1744. num_of_entries++;
  1745. #endif /* DISP_PARTIAL */
  1746. } /* end while directory entries left to read */
  1747. if (status != HT_PARTIAL_CONTENT)
  1748. _HTProgress(OPERATION_OK);
  1749. else
  1750. CTRACE((tfp, "Reading the directory interrupted by user\n"));
  1751. /*
  1752. * Run through tree printing out in order.
  1753. */
  1754. {
  1755. HTBTElement *next_element = HTBTree_next(bt, NULL);
  1756. /* pick up the first element of the list */
  1757. int num_of_entries_output = 0; /* lines counter */
  1758. char state;
  1759. /* I for initial (.. file),
  1760. D for directory file,
  1761. F for file */
  1762. #ifdef DIRED_SUPPORT
  1763. char test;
  1764. #endif /* DIRED_SUPPORT */
  1765. state = 'I';
  1766. while (next_element != NULL) {
  1767. DIRED *entry;
  1768. #ifndef DISP_PARTIAL
  1769. if (num_of_entries_output % HTMAX(display_lines, 10) == 0) {
  1770. if (HTCheckForInterrupt()) {
  1771. _HTProgress(TRANSFER_INTERRUPTED);
  1772. status = HT_PARTIAL_CONTENT;
  1773. break;
  1774. }
  1775. }
  1776. #endif
  1777. StrAllocCopy(tmpfilename, localname);
  1778. /*
  1779. * If filename is not root directory.
  1780. */
  1781. LYAddPathSep(&tmpfilename);
  1782. entry = (DIRED *) (HTBTree_object(next_element));
  1783. /*
  1784. * Append the current entry's filename to the path.
  1785. */
  1786. StrAllocCat(tmpfilename, entry->file_name);
  1787. HTSimplify(tmpfilename);
  1788. /*
  1789. * Output the directory entry.
  1790. */
  1791. if (strcmp(DIRED_NAME(HTBTree_object(next_element)), "..")) {
  1792. #ifdef DIRED_SUPPORT
  1793. test = (DIRED_BLOK(HTBTree_object(next_element))
  1794. == 'D' ? 'D' : 'F');
  1795. if (state != test) {
  1796. #ifndef LONG_LIST
  1797. if (dir_list_style == FILES_FIRST) {
  1798. if (state == 'F') {
  1799. END(HTML_DIR);
  1800. PUTC('\n');
  1801. }
  1802. } else if (dir_list_style != MIXED_STYLE)
  1803. if (state == 'D') {
  1804. END(HTML_DIR);
  1805. PUTC('\n');
  1806. }
  1807. #endif /* !LONG_LIST */
  1808. state =
  1809. (char) (DIRED_BLOK(HTBTree_object(next_element))
  1810. == 'D' ? 'D' : 'F');
  1811. if (preformatted) {
  1812. END(HTML_PRE);
  1813. PUTC('\n');
  1814. preformatted = FALSE;
  1815. }
  1816. START(HTML_H2);
  1817. if (dir_list_style != MIXED_STYLE) {
  1818. START(HTML_EM);
  1819. PUTS(state == 'D'
  1820. ? LABEL_SUBDIRECTORIES
  1821. : LABEL_FILES);
  1822. END(HTML_EM);
  1823. }
  1824. END(HTML_H2);
  1825. PUTC('\n');
  1826. #ifndef LONG_LIST
  1827. START(HTML_DIR);
  1828. PUTC('\n');
  1829. #endif /* !LONG_LIST */
  1830. }
  1831. #else
  1832. if (state != DIRED_BLOK(HTBTree_object(next_element))) {
  1833. #ifndef LONG_LIST
  1834. if (state == 'D') {
  1835. END(HTML_DIR);
  1836. PUTC('\n');
  1837. }
  1838. #endif /* !LONG_LIST */
  1839. state =
  1840. (char) (DIRED_BLOK(HTBTree_object(next_element))
  1841. == 'D' ? 'D' : 'F');
  1842. if (preformatted) {
  1843. END(HTML_PRE);
  1844. PUTC('\n');
  1845. preformatted = FALSE;
  1846. }
  1847. START(HTML_H2);
  1848. START(HTML_EM);
  1849. PUTS(state == 'D'
  1850. ? LABEL_SUBDIRECTORIES
  1851. : LABEL_FILES);
  1852. END(HTML_EM);
  1853. END(HTML_H2);
  1854. PUTC('\n');
  1855. #ifndef LONG_LIST
  1856. START(HTML_DIR);
  1857. PUTC('\n');
  1858. #endif /* !LONG_LIST */
  1859. }
  1860. #endif /* DIRED_SUPPORT */
  1861. #ifndef LONG_LIST
  1862. START(HTML_LI);
  1863. #endif /* !LONG_LIST */
  1864. }
  1865. if (!preformatted) {
  1866. START(HTML_PRE);
  1867. PUTC('\n');
  1868. preformatted = TRUE;
  1869. }
  1870. #ifdef LONG_LIST
  1871. LYListFmtParse(list_format, entry, tmpfilename, target, tail);
  1872. #else
  1873. HTDirEntry(target, tail, entry->file_name);
  1874. PUTS(entry->file_name);
  1875. END(HTML_A);
  1876. MAYBE_END(HTML_LI);
  1877. PUTC('\n');
  1878. #endif /* LONG_LIST */
  1879. next_element = HTBTree_next(bt, next_element);
  1880. /* pick up the next element of the list;
  1881. if none, return NULL */
  1882. /* optimize for expensive operation: */
  1883. #ifdef DISP_PARTIAL
  1884. if (num_of_entries_output %
  1885. (partial_threshold > 0 ? partial_threshold : display_lines)
  1886. == 0) {
  1887. /* num_of_entries, num_of_entries_output... */
  1888. /* HTReadProgress...(bytes, 0); */
  1889. HTDisplayPartial();
  1890. if (HTCheckForInterrupt()) {
  1891. _HTProgress(TRANSFER_INTERRUPTED);
  1892. status = HT_PARTIAL_CONTENT;
  1893. break;
  1894. }
  1895. }
  1896. num_of_entries_output++;
  1897. #endif /* DISP_PARTIAL */
  1898. } /* end while next_element */
  1899. if (status == HT_LOADED) {
  1900. if (state == 'I') {
  1901. START(HTML_P);
  1902. PUTS("Empty Directory");
  1903. }
  1904. #ifndef LONG_LIST
  1905. else
  1906. END(HTML_DIR);
  1907. #endif /* !LONG_LIST */
  1908. }
  1909. } /* end printing out the tree in order */
  1910. if (preformatted) {
  1911. END(HTML_PRE);
  1912. PUTC('\n');
  1913. }
  1914. END(HTML_BODY);
  1915. PUTC('\n');
  1916. FREE(tmpfilename);
  1917. FREE(tail);
  1918. HTBTreeAndObject_free(bt);
  1919. if (status == HT_LOADED) {
  1920. if (HTDirReadme == HT_DIR_README_BOTTOM)
  1921. do_readme(target, localname);
  1922. FREE_TARGET;
  1923. } else {
  1924. ABORT_TARGET;
  1925. }
  1926. HTFinishDisplayPartial();
  1927. return status; /* document loaded, maybe partial */
  1928. }
  1929. #endif /* HAVE_READDIR */
  1930. #ifndef VMS
  1931. int HTStat(const char *filename,
  1932. struct stat *data)
  1933. {
  1934. int result = -1;
  1935. size_t len = strlen(filename);
  1936. if (len != 0 && LYIsPathSep(filename[len - 1])) {
  1937. char *temp_name = NULL;
  1938. HTSprintf0(&temp_name, "%s.", filename);
  1939. result = HTStat(temp_name, data);
  1940. FREE(temp_name);
  1941. } else {
  1942. result = stat(filename, data);
  1943. #ifdef _WINDOWS
  1944. /*
  1945. * Someone claims that stat() doesn't give the proper result for a
  1946. * directory on Windows.
  1947. */
  1948. if (result == -1
  1949. && access(filename, 0) == 0) {
  1950. data->st_mode = S_IFDIR;
  1951. result = 0;
  1952. }
  1953. #endif
  1954. }
  1955. return result;
  1956. }
  1957. #endif
  1958. #ifdef VMS
  1959. #define FOPEN_MODE(bin) "r", "shr=put", "shr=upd"
  1960. #define DOT_STRING "._-" /* FIXME: should we check if suffix is after ']' or ':' ? */
  1961. #else
  1962. #define FOPEN_MODE(bin) (bin ? BIN_R : "r")
  1963. #define DOT_STRING "."
  1964. #endif
  1965. static int decompressAndParse(HTParentAnchor *anchor,
  1966. HTFormat format_out,
  1967. HTStream *sink,
  1968. char *nodename GCC_UNUSED,
  1969. char *filename,
  1970. HTAtom *myEncoding,
  1971. HTFormat format,
  1972. int *statusp)
  1973. {
  1974. HTAtom *encoding = 0;
  1975. #ifdef USE_ZLIB
  1976. FILE *zzfp = 0;
  1977. gzFile gzfp = 0;
  1978. #endif /* USE_ZLIB */
  1979. #ifdef USE_BZLIB
  1980. BZFILE *bzfp = 0;
  1981. #endif /* USE_ZLIB */
  1982. #if defined(USE_ZLIB) || defined(USE_BZLIB)
  1983. CompressFileType internal_decompress = cftNone;
  1984. BOOL failed_decompress = NO;
  1985. #endif
  1986. int rootlen = 0;
  1987. char *localname = filename;
  1988. int bin;
  1989. FILE *fp;
  1990. #ifdef VMS
  1991. /*
  1992. * Assume that the file is in Unix-style syntax if it contains a '/' after
  1993. * the leading one. @@
  1994. */
  1995. localname = (strchr(localname + 1, '/')
  1996. ? HTVMS_name(nodename, localname)
  1997. : localname + 1);
  1998. #endif /* VMS */
  1999. bin = HTCompressFileType(filename, ".", &rootlen) != cftNone;
  2000. fp = fopen(localname, FOPEN_MODE(bin));
  2001. #ifdef VMS
  2002. /*
  2003. * If the file wasn't VMS syntax, then perhaps it is Ultrix.
  2004. */
  2005. if (!fp) {
  2006. char *ultrixname = 0;
  2007. CTRACE((tfp, "HTLoadFile: Can't open as %s\n", localname));
  2008. HTSprintf0(&ultrixname, "%s::\"%s\"", nodename, filename);
  2009. fp = fopen(ultrixname, FOPEN_MODE(bin));
  2010. if (!fp) {
  2011. CTRACE((tfp, "HTLoadFile: Can't open as %s\n", ultrixname));
  2012. }
  2013. FREE(ultrixname);
  2014. }
  2015. #endif /* VMS */
  2016. CTRACE((tfp, "HTLoadFile: Opening `%s' gives %p\n", localname, fp));
  2017. if (fp) { /* Good! */
  2018. if (HTEditable(localname)) {
  2019. HTAtom *put = HTAtom_for("PUT");
  2020. HTList *methods = HTAnchor_methods(anchor);
  2021. if (HTList_indexOf(methods, put) == (-1)) {
  2022. HTList_addObject(methods, put);
  2023. }
  2024. }
  2025. /*
  2026. * Fake a Content-Encoding for compressed files. - FM
  2027. */
  2028. if (!IsUnityEnc(myEncoding)) {
  2029. /*
  2030. * We already know from the call to HTFileFormat that
  2031. * this is a compressed file, no need to look at the filename
  2032. * again. - kw
  2033. */
  2034. CompressFileType method = HTEncodingToCompressType(HTAtom_name(myEncoding));
  2035. #define isDOWNLOAD(m) (strcmp(format_out->name, "www/download") && (method == m))
  2036. #ifdef USE_ZLIB
  2037. if (isDOWNLOAD(cftGzip)) {
  2038. fclose(fp);
  2039. gzfp = gzopen(localname, BIN_R);
  2040. CTRACE((tfp, "HTLoadFile: gzopen of `%s' gives %p\n",
  2041. localname, gzfp));
  2042. internal_decompress = cftGzip;
  2043. } else if (isDOWNLOAD(cftDeflate)) {
  2044. zzfp = fp;
  2045. fp = 0;
  2046. CTRACE((tfp, "HTLoadFile: zzopen of `%s' gives %p\n",
  2047. localname, zzfp));
  2048. internal_decompress = cftDeflate;
  2049. } else
  2050. #endif /* USE_ZLIB */
  2051. #ifdef USE_BZLIB
  2052. if (isDOWNLOAD(cftBzip2)) {
  2053. fclose(fp);
  2054. bzfp = BZ2_bzopen(localname, BIN_R);
  2055. CTRACE((tfp, "HTLoadFile: bzopen of `%s' gives %p\n",
  2056. localname, bzfp));
  2057. internal_decompress = cftBzip2;
  2058. } else
  2059. #endif /* USE_BZLIB */
  2060. {
  2061. StrAllocCopy(anchor->content_type, format->name);
  2062. StrAllocCopy(anchor->content_encoding, HTAtom_name(myEncoding));
  2063. format = HTAtom_for("www/compressed");
  2064. }
  2065. } else {
  2066. CompressFileType cft = HTCompressFileType(localname, DOT_STRING, &rootlen);
  2067. if (cft != cftNone) {
  2068. char *cp = NULL;
  2069. StrAllocCopy(cp, localname);
  2070. cp[rootlen] = '\0';
  2071. format = HTFileFormat(cp, &encoding, NULL);
  2072. FREE(cp);
  2073. format = HTCharsetFormat(format, anchor,
  2074. UCLYhndl_HTFile_for_unspec);
  2075. StrAllocCopy(anchor->content_type, format->name);
  2076. }
  2077. switch (cft) {
  2078. case cftCompress:
  2079. StrAllocCopy(anchor->content_encoding, "x-compress");
  2080. format = HTAtom_for("www/compressed");
  2081. break;
  2082. case cftDeflate:
  2083. StrAllocCopy(anchor->content_encoding, "x-deflate");
  2084. #ifdef USE_ZLIB
  2085. if (strcmp(format_out->name, "www/download") != 0) {
  2086. zzfp = fp;
  2087. fp = 0;
  2088. CTRACE((tfp, "HTLoadFile: zzopen of `%s' gives %p\n",
  2089. localname, zzfp));
  2090. internal_decompress = cftDeflate;
  2091. }
  2092. #else /* USE_ZLIB */
  2093. format = HTAtom_for("www/compressed");
  2094. #endif /* USE_ZLIB */
  2095. break;
  2096. case cftGzip:
  2097. StrAllocCopy(anchor->content_encoding, "x-gzip");
  2098. #ifdef USE_ZLIB
  2099. if (strcmp(format_out->name, "www/download") != 0) {
  2100. fclose(fp);
  2101. gzfp = gzopen(localname, BIN_R);
  2102. CTRACE((tfp, "HTLoadFile: gzopen of `%s' gives %p\n",
  2103. localname, gzfp));
  2104. internal_decompress = cftGzip;
  2105. }
  2106. #else /* USE_ZLIB */
  2107. format = HTAtom_for("www/compressed");
  2108. #endif /* USE_ZLIB */
  2109. break;
  2110. case cftBzip2:
  2111. StrAllocCopy(anchor->content_encoding, "x-bzip2");
  2112. #ifdef USE_BZLIB
  2113. if (strcmp(format_out->name, "www/download") != 0) {
  2114. fclose(fp);
  2115. bzfp = BZ2_bzopen(localname, BIN_R);
  2116. CTRACE((tfp, "HTLoadFile: bzopen of `%s' gives %p\n",
  2117. localname, bzfp));
  2118. internal_decompress = cftBzip2;
  2119. }
  2120. #else /* USE_BZLIB */
  2121. format = HTAtom_for("www/compressed");
  2122. #endif /* USE_BZLIB */
  2123. break;
  2124. case cftNone:
  2125. break;
  2126. }
  2127. }
  2128. #if defined(USE_ZLIB) || defined(USE_BZLIB)
  2129. if (internal_decompress != cftNone) {
  2130. switch (internal_decompress) {
  2131. #ifdef USE_ZLIB
  2132. case cftDeflate:
  2133. failed_decompress = (zzfp == 0);
  2134. break;
  2135. case cftCompress:
  2136. case cftGzip:
  2137. failed_decompress = (gzfp == 0);
  2138. break;
  2139. #endif
  2140. #ifdef USE_BZLIB
  2141. case cftBzip2:
  2142. failed_decompress = (bzfp == 0);
  2143. break;
  2144. #endif
  2145. default:
  2146. failed_decompress = YES;
  2147. break;
  2148. }
  2149. if (failed_decompress) {
  2150. *statusp = HTLoadError(NULL,
  2151. -(HT_ERROR),
  2152. FAILED_OPEN_COMPRESSED_FILE);
  2153. } else {
  2154. char *sugfname = NULL;
  2155. if (anchor->SugFname) {
  2156. StrAllocCopy(sugfname, anchor->SugFname);
  2157. } else {
  2158. char *anchor_path = HTParse(anchor->address, "",
  2159. PARSE_PATH + PARSE_PUNCTUATION);
  2160. char *lastslash;
  2161. HTUnEscape(anchor_path);
  2162. lastslash = strrchr(anchor_path, '/');
  2163. if (lastslash)
  2164. StrAllocCopy(sugfname, lastslash + 1);
  2165. FREE(anchor_path);
  2166. }
  2167. FREE(anchor->content_encoding);
  2168. if (sugfname && *sugfname)
  2169. HTCheckFnameForCompression(&sugfname, anchor,
  2170. TRUE);
  2171. if (sugfname && *sugfname)
  2172. StrAllocCopy(anchor->SugFname, sugfname);
  2173. FREE(sugfname);
  2174. #ifdef USE_BZLIB
  2175. if (bzfp)
  2176. *statusp = HTParseBzFile(format, format_out,
  2177. anchor,
  2178. bzfp, sink);
  2179. #endif
  2180. #ifdef USE_ZLIB
  2181. if (gzfp)
  2182. *statusp = HTParseGzFile(format, format_out,
  2183. anchor,
  2184. gzfp, sink);
  2185. else if (zzfp)
  2186. *statusp = HTParseZzFile(format, format_out,
  2187. anchor,
  2188. zzfp, sink);
  2189. #endif
  2190. }
  2191. } else
  2192. #endif /* USE_ZLIB || USE_BZLIB */
  2193. {
  2194. *statusp = HTParseFile(format, format_out, anchor, fp, sink);
  2195. fclose(fp);
  2196. }
  2197. return TRUE;
  2198. } /* If successful open */
  2199. return FALSE;
  2200. }
  2201. /* Load a document.
  2202. * ----------------
  2203. *
  2204. * On entry:
  2205. * addr must point to the fully qualified hypertext reference.
  2206. * This is the physical address of the file
  2207. *
  2208. * On exit:
  2209. * returns <0 Error has occurred.
  2210. * HTLOADED OK
  2211. *
  2212. */
  2213. int HTLoadFile(const char *addr,
  2214. HTParentAnchor *anchor,
  2215. HTFormat format_out,
  2216. HTStream *sink)
  2217. {
  2218. char *filename = NULL;
  2219. char *acc_method = NULL;
  2220. HTFormat format;
  2221. char *nodename = NULL;
  2222. char *newname = NULL; /* Simplified name of file */
  2223. HTAtom *myEncoding = NULL; /* enc of this file, may be gzip etc. */
  2224. int status = -1;
  2225. #ifndef DISABLE_FTP
  2226. char *ftp_newhost;
  2227. #endif
  2228. #ifdef VMS
  2229. struct stat stat_info;
  2230. #endif /* VMS */
  2231. /*
  2232. * Reduce the filename to a basic form (hopefully unique!).
  2233. */
  2234. StrAllocCopy(newname, addr);
  2235. filename = HTParse(newname, "", PARSE_PATH | PARSE_PUNCTUATION);
  2236. nodename = HTParse(newname, "", PARSE_HOST);
  2237. /*
  2238. * If access is ftp, or file is on another host, invoke ftp now.
  2239. */
  2240. acc_method = HTParse(newname, "", PARSE_ACCESS);
  2241. if (strcmp("ftp", acc_method) == 0 ||
  2242. (!LYSameHostname("localhost", nodename) &&
  2243. !LYSameHostname(nodename, HTHostName()))) {
  2244. status = -1;
  2245. FREE(newname);
  2246. FREE(filename);
  2247. FREE(nodename);
  2248. FREE(acc_method);
  2249. #ifndef DISABLE_FTP
  2250. ftp_newhost = HTParse(addr, "", PARSE_HOST);
  2251. if (strcmp(ftp_lasthost, ftp_newhost))
  2252. ftp_local_passive = ftp_passive;
  2253. status = HTFTPLoad(addr, anchor, format_out, sink);
  2254. if (ftp_passive == ftp_local_passive) {
  2255. if ((status >= 400) || (status < 0)) {
  2256. ftp_local_passive = !ftp_passive;
  2257. status = HTFTPLoad(addr, anchor, format_out, sink);
  2258. }
  2259. }
  2260. free(ftp_lasthost);
  2261. ftp_lasthost = ftp_newhost;
  2262. #endif /* DISABLE_FTP */
  2263. return status;
  2264. } else {
  2265. FREE(newname);
  2266. FREE(acc_method);
  2267. }
  2268. #if defined(VMS) || defined(USE_DOS_DRIVES)
  2269. HTUnEscape(filename);
  2270. #endif /* VMS */
  2271. /*
  2272. * Determine the format and encoding mapped to any suffix.
  2273. */
  2274. if (anchor->content_type && anchor->content_encoding) {
  2275. /*
  2276. * If content_type and content_encoding are BOTH already set in the
  2277. * anchor object, we believe it and don't try to derive format and
  2278. * encoding from the filename. - kw
  2279. */
  2280. format = HTAtom_for(anchor->content_type);
  2281. myEncoding = HTAtom_for(anchor->content_encoding);
  2282. } else {
  2283. int default_UCLYhndl = UCLYhndl_HTFile_for_unspec;
  2284. if (force_old_UCLYhndl_on_reload) {
  2285. force_old_UCLYhndl_on_reload = FALSE;
  2286. default_UCLYhndl = forced_UCLYhdnl;
  2287. }
  2288. format = HTFileFormat(filename, &myEncoding, NULL);
  2289. /*
  2290. * Check the format for an extended MIME charset value, and act on it
  2291. * if present. Otherwise, assume what is indicated by the last
  2292. * parameter (fallback will effectively be UCLYhndl_for_unspec, by
  2293. * default ISO-8859-1). - kw
  2294. */
  2295. format = HTCharsetFormat(format, anchor, default_UCLYhndl);
  2296. }
  2297. #ifdef VMS
  2298. /*
  2299. * Check to see if the 'filename' is in fact a directory. If it is create
  2300. * a new hypertext object containing a list of files and subdirectories
  2301. * contained in the directory. All of these are links to the directories
  2302. * or files listed.
  2303. */
  2304. if (HTStat(filename, &stat_info) == -1) {
  2305. CTRACE((tfp, "HTLoadFile: Can't stat %s\n", filename));
  2306. } else {
  2307. if (S_ISDIR(stat_info.st_mode)) {
  2308. if (HTDirAccess == HT_DIR_FORBID) {
  2309. FREE(filename);
  2310. FREE(nodename);
  2311. return HTLoadError(sink, 403, DISALLOWED_DIR_SCAN);
  2312. }
  2313. if (HTDirAccess == HT_DIR_SELECTIVE) {
  2314. char *enable_file_name = NULL;
  2315. HTSprintf0(&enable_file_name, "%s/%s", filename, HT_DIR_ENABLE_FILE);
  2316. if (HTStat(enable_file_name, &stat_info) == -1) {
  2317. FREE(filename);
  2318. FREE(nodename);
  2319. FREE(enable_file_name);
  2320. return HTLoadError(sink, 403, DISALLOWED_SELECTIVE_ACCESS);
  2321. }
  2322. }
  2323. FREE(filename);
  2324. FREE(nodename);
  2325. return HTVMSBrowseDir(addr, anchor, format_out, sink);
  2326. }
  2327. }
  2328. if (decompressAndParse(anchor,
  2329. format_out,
  2330. sink,
  2331. nodename,
  2332. filename,
  2333. myEncoding,
  2334. format,
  2335. &status)) {
  2336. FREE(nodename);
  2337. FREE(filename);
  2338. return status;
  2339. }
  2340. FREE(filename);
  2341. #else /* not VMS: */
  2342. FREE(filename);
  2343. /*
  2344. * For unix, we try to translate the name into the name of a transparently
  2345. * mounted file.
  2346. *
  2347. * Not allowed in secure (HTClientHost) situations. TBL 921019
  2348. */
  2349. #ifndef NO_UNIX_IO
  2350. /* Need protection here for telnet server but not httpd server. */
  2351. if (!HTSecure) { /* try local file system */
  2352. char *localname = HTLocalName(addr);
  2353. struct stat dir_info;
  2354. #ifdef HAVE_READDIR
  2355. /*
  2356. * Multiformat handling.
  2357. *
  2358. * If needed, scan directory to find a good file. Bug: We don't stat
  2359. * the file to find the length.
  2360. */
  2361. if ((strlen(localname) > strlen(MULTI_SUFFIX)) &&
  2362. (0 == strcmp(localname + strlen(localname) - strlen(MULTI_SUFFIX),
  2363. MULTI_SUFFIX))) {
  2364. DIR *dp = 0;
  2365. BOOL forget_multi = NO;
  2366. STRUCT_DIRENT *dirbuf;
  2367. float best = (float) NO_VALUE_FOUND; /* So far best is bad */
  2368. HTFormat best_rep = NULL; /* Set when rep found */
  2369. HTAtom *best_enc = NULL;
  2370. char *best_name = NULL; /* Best dir entry so far */
  2371. char *base = strrchr(localname, '/');
  2372. int baselen = 0;
  2373. if (!base || base == localname) {
  2374. forget_multi = YES;
  2375. } else {
  2376. *base++ = '\0'; /* Just got directory name */
  2377. baselen = strlen(base) - strlen(MULTI_SUFFIX);
  2378. base[baselen] = '\0'; /* Chop off suffix */
  2379. dp = opendir(localname);
  2380. }
  2381. if (forget_multi || !dp) {
  2382. FREE(localname);
  2383. FREE(nodename);
  2384. return HTLoadError(sink, 500, FAILED_DIR_SCAN);
  2385. }
  2386. while ((dirbuf = readdir(dp)) != NULL) {
  2387. /*
  2388. * While there are directory entries to be read...
  2389. */
  2390. #ifdef STRUCT_DIRENT__D_INO
  2391. if (dirbuf->d_ino == 0)
  2392. continue; /* if the entry is not being used, skip it */
  2393. #endif
  2394. if ((int) strlen(dirbuf->d_name) > baselen && /* Match? */
  2395. !strncmp(dirbuf->d_name, base, baselen)) {
  2396. HTAtom *enc;
  2397. HTFormat rep = HTFileFormat(dirbuf->d_name, &enc, NULL);
  2398. float filevalue = HTFileValue(dirbuf->d_name);
  2399. float value = HTStackValue(rep, format_out,
  2400. filevalue,
  2401. 0L /* @@@@@@ */ );
  2402. if (value <= 0.0) {
  2403. int rootlen = 0;
  2404. const char *atomname = NULL;
  2405. CompressFileType cft =
  2406. HTCompressFileType(dirbuf->d_name, ".", &rootlen);
  2407. char *cp = NULL;
  2408. enc = NULL;
  2409. if (cft != cftNone) {
  2410. StrAllocCopy(cp, dirbuf->d_name);
  2411. cp[rootlen] = '\0';
  2412. format = HTFileFormat(cp, NULL, NULL);
  2413. FREE(cp);
  2414. value = HTStackValue(format, format_out,
  2415. filevalue, 0);
  2416. switch (cft) {
  2417. case cftCompress:
  2418. atomname = "application/x-compressed";
  2419. break;
  2420. case cftGzip:
  2421. atomname = "application/x-gzip";
  2422. break;
  2423. case cftDeflate:
  2424. atomname = "application/x-deflate";
  2425. break;
  2426. case cftBzip2:
  2427. atomname = "application/x-bzip2";
  2428. break;
  2429. case cftNone:
  2430. break;
  2431. }
  2432. }
  2433. if (atomname != NULL) {
  2434. value = HTStackValue(format, format_out,
  2435. filevalue, 0);
  2436. if (value <= 0.0) {
  2437. format = HTAtom_for(atomname);
  2438. value = HTStackValue(format, format_out,
  2439. filevalue, 0);
  2440. }
  2441. if (value <= 0.0) {
  2442. format = HTAtom_for("www/compressed");
  2443. value = HTStackValue(format, format_out,
  2444. filevalue, 0);
  2445. }
  2446. }
  2447. }
  2448. if (value != NO_VALUE_FOUND) {
  2449. CTRACE((tfp,
  2450. "HTLoadFile: value of presenting %s is %f\n",
  2451. HTAtom_name(rep), value));
  2452. if (value > best) {
  2453. best_rep = rep;
  2454. best_enc = enc;
  2455. best = value;
  2456. StrAllocCopy(best_name, dirbuf->d_name);
  2457. }
  2458. } /* if best so far */
  2459. }
  2460. /* if match */
  2461. } /* end while directory entries left to read */
  2462. closedir(dp);
  2463. if (best_rep) {
  2464. format = best_rep;
  2465. myEncoding = best_enc;
  2466. base[-1] = '/'; /* Restore directory name */
  2467. base[0] = '\0';
  2468. StrAllocCat(localname, best_name);
  2469. FREE(best_name);
  2470. } else { /* If not found suitable file */
  2471. FREE(localname);
  2472. FREE(nodename);
  2473. return HTLoadError(sink, 403, FAILED_NO_REPRESENTATION);
  2474. }
  2475. /*NOTREACHED */
  2476. }
  2477. /* if multi suffix */
  2478. /*
  2479. * Check to see if the 'localname' is in fact a directory. If it is
  2480. * create a new hypertext object containing a list of files and
  2481. * subdirectories contained in the directory. All of these are links
  2482. * to the directories or files listed. NB This assumes the existence
  2483. * of a type 'STRUCT_DIRENT', which will hold the directory entry, and
  2484. * a type 'DIR' which is used to point to the current directory being
  2485. * read.
  2486. */
  2487. #if defined(USE_DOS_DRIVES)
  2488. if (strlen(localname) == 2 && LYIsDosDrive(localname))
  2489. LYAddPathSep(&localname);
  2490. #endif
  2491. if (HTStat(localname, &dir_info) == -1) /* get file information */
  2492. {
  2493. /* if can't read file information */
  2494. CTRACE((tfp, "HTLoadFile: can't stat %s\n", localname));
  2495. } else { /* Stat was OK */
  2496. if (S_ISDIR(dir_info.st_mode)) {
  2497. /*
  2498. * If localname is a directory.
  2499. */
  2500. DIR *dp;
  2501. struct stat file_info;
  2502. CTRACE((tfp, "%s is a directory\n", localname));
  2503. /*
  2504. * Check directory access. Selective access means only those
  2505. * directories containing a marker file can be browsed.
  2506. */
  2507. if (HTDirAccess == HT_DIR_FORBID) {
  2508. FREE(localname);
  2509. FREE(nodename);
  2510. return HTLoadError(sink, 403, DISALLOWED_DIR_SCAN);
  2511. }
  2512. if (HTDirAccess == HT_DIR_SELECTIVE) {
  2513. char *enable_file_name = NULL;
  2514. HTSprintf0(&enable_file_name, "%s/%s", localname, HT_DIR_ENABLE_FILE);
  2515. if (stat(enable_file_name, &file_info) != 0) {
  2516. FREE(localname);
  2517. FREE(nodename);
  2518. FREE(enable_file_name);
  2519. return HTLoadError(sink, 403, DISALLOWED_SELECTIVE_ACCESS);
  2520. }
  2521. }
  2522. CTRACE((tfp, "Opening directory %s\n", localname));
  2523. dp = opendir(localname);
  2524. if (!dp) {
  2525. FREE(localname);
  2526. FREE(nodename);
  2527. return HTLoadError(sink, 403, FAILED_DIR_UNREADABLE);
  2528. }
  2529. /*
  2530. * Directory access is allowed and possible.
  2531. */
  2532. status = print_local_dir(dp, localname,
  2533. anchor, format_out, sink);
  2534. closedir(dp);
  2535. FREE(localname);
  2536. FREE(nodename);
  2537. return status; /* document loaded, maybe partial */
  2538. }
  2539. /* end if localname is a directory */
  2540. if (S_ISREG(dir_info.st_mode)) {
  2541. #ifdef INT_MAX
  2542. if (dir_info.st_size <= INT_MAX)
  2543. #endif
  2544. anchor->content_length = dir_info.st_size;
  2545. }
  2546. } /* end if file stat worked */
  2547. /* End of directory reading section
  2548. */
  2549. #endif /* HAVE_READDIR */
  2550. if (decompressAndParse(anchor,
  2551. format_out,
  2552. sink,
  2553. nodename,
  2554. localname,
  2555. myEncoding,
  2556. format,
  2557. &status)) {
  2558. FREE(nodename);
  2559. FREE(localname);
  2560. return status;
  2561. }
  2562. FREE(localname);
  2563. } /* local unix file system */
  2564. #endif /* !NO_UNIX_IO */
  2565. #endif /* VMS */
  2566. #ifndef DECNET
  2567. /*
  2568. * Now, as transparently mounted access has failed, we try FTP.
  2569. */
  2570. {
  2571. /*
  2572. * Deal with case-sensitivity differences on VMS versus Unix.
  2573. */
  2574. #ifdef VMS
  2575. if (strcasecomp(nodename, HTHostName()) != 0)
  2576. #else
  2577. if (strcmp(nodename, HTHostName()) != 0)
  2578. #endif /* VMS */
  2579. {
  2580. status = -1;
  2581. FREE(nodename);
  2582. if (strncmp(addr, "file://localhost", 16)) {
  2583. /* never go to ftp site when URL
  2584. * is file://localhost
  2585. */
  2586. #ifndef DISABLE_FTP
  2587. status = HTFTPLoad(addr, anchor, format_out, sink);
  2588. #endif /* DISABLE_FTP */
  2589. }
  2590. return status;
  2591. }
  2592. FREE(nodename);
  2593. }
  2594. #endif /* !DECNET */
  2595. /*
  2596. * All attempts have failed.
  2597. */
  2598. {
  2599. CTRACE((tfp, "Can't open `%s', errno=%d\n", addr, SOCKET_ERRNO));
  2600. return HTLoadError(sink, 403, FAILED_FILE_UNREADABLE);
  2601. }
  2602. }
  2603. static const char *program_paths[pp_Last];
  2604. /*
  2605. * Given a program number, return its path
  2606. */
  2607. const char *HTGetProgramPath(ProgramPaths code)
  2608. {
  2609. const char *result = NULL;
  2610. if (code > ppUnknown && code < pp_Last)
  2611. result = program_paths[code];
  2612. return result;
  2613. }
  2614. /*
  2615. * Store a program's path. The caller must allocate the string used for 'path',
  2616. * since HTInitProgramPaths() may free it.
  2617. */
  2618. void HTSetProgramPath(ProgramPaths code, const char *path)
  2619. {
  2620. if (code > ppUnknown && code < pp_Last) {
  2621. program_paths[code] = isEmpty(path) ? 0 : path;
  2622. }
  2623. }
  2624. /*
  2625. * Reset the list of known program paths to the ones that are compiled-in
  2626. */
  2627. void HTInitProgramPaths(void)
  2628. {
  2629. ProgramPaths code;
  2630. int n;
  2631. const char *path;
  2632. const char *test;
  2633. for (n = (int) ppUnknown + 1; n < (int) pp_Last; ++n) {
  2634. switch (code = (ProgramPaths) n) {
  2635. #ifdef BZIP2_PATH
  2636. case ppBZIP2:
  2637. path = BZIP2_PATH;
  2638. break;
  2639. #endif
  2640. #ifdef CHMOD_PATH
  2641. case ppCHMOD:
  2642. path = CHMOD_PATH;
  2643. break;
  2644. #endif
  2645. #ifdef COMPRESS_PATH
  2646. case ppCOMPRESS:
  2647. path = COMPRESS_PATH;
  2648. break;
  2649. #endif
  2650. #ifdef COPY_PATH
  2651. case ppCOPY:
  2652. path = COPY_PATH;
  2653. break;
  2654. #endif
  2655. #ifdef CSWING_PATH
  2656. case ppCSWING:
  2657. path = CSWING_PATH;
  2658. break;
  2659. #endif
  2660. #ifdef GZIP_PATH
  2661. case ppGZIP:
  2662. path = GZIP_PATH;
  2663. break;
  2664. #endif
  2665. #ifdef INFLATE_PATH
  2666. case ppINFLATE:
  2667. path = INFLATE_PATH;
  2668. break;
  2669. #endif
  2670. #ifdef INSTALL_PATH
  2671. case ppINSTALL:
  2672. path = INSTALL_PATH;
  2673. break;
  2674. #endif
  2675. #ifdef MKDIR_PATH
  2676. case ppMKDIR:
  2677. path = MKDIR_PATH;
  2678. break;
  2679. #endif
  2680. #ifdef MV_PATH
  2681. case ppMV:
  2682. path = MV_PATH;
  2683. break;
  2684. #endif
  2685. #ifdef RLOGIN_PATH
  2686. case ppRLOGIN:
  2687. path = RLOGIN_PATH;
  2688. break;
  2689. #endif
  2690. #ifdef RM_PATH
  2691. case ppRM:
  2692. path = RM_PATH;
  2693. break;
  2694. #endif
  2695. #ifdef RMDIR_PATH
  2696. case ppRMDIR:
  2697. path = RMDIR_PATH;
  2698. break;
  2699. #endif
  2700. #ifdef SETFONT_PATH
  2701. case ppSETFONT:
  2702. path = SETFONT_PATH;
  2703. break;
  2704. #endif
  2705. #ifdef TAR_PATH
  2706. case ppTAR:
  2707. path = TAR_PATH;
  2708. break;
  2709. #endif
  2710. #ifdef TELNET_PATH
  2711. case ppTELNET:
  2712. path = TELNET_PATH;
  2713. break;
  2714. #endif
  2715. #ifdef TN3270_PATH
  2716. case ppTN3270:
  2717. path = TN3270_PATH;
  2718. break;
  2719. #endif
  2720. #ifdef TOUCH_PATH
  2721. case ppTOUCH:
  2722. path = TOUCH_PATH;
  2723. break;
  2724. #endif
  2725. #ifdef UNCOMPRESS_PATH
  2726. case ppUNCOMPRESS:
  2727. path = UNCOMPRESS_PATH;
  2728. break;
  2729. #endif
  2730. #ifdef UNZIP_PATH
  2731. case ppUNZIP:
  2732. path = UNZIP_PATH;
  2733. break;
  2734. #endif
  2735. #ifdef UUDECODE_PATH
  2736. case ppUUDECODE:
  2737. path = UUDECODE_PATH;
  2738. break;
  2739. #endif
  2740. #ifdef ZCAT_PATH
  2741. case ppZCAT:
  2742. path = ZCAT_PATH;
  2743. break;
  2744. #endif
  2745. #ifdef ZIP_PATH
  2746. case ppZIP:
  2747. path = ZIP_PATH;
  2748. break;
  2749. #endif
  2750. default:
  2751. path = NULL;
  2752. break;
  2753. }
  2754. test = HTGetProgramPath(code);
  2755. if (test != NULL && test != path) {
  2756. free((char *) test);
  2757. }
  2758. HTSetProgramPath(code, path);
  2759. }
  2760. }
  2761. /*
  2762. * Protocol descriptors
  2763. */
  2764. #ifdef GLOBALDEF_IS_MACRO
  2765. #define _HTFILE_C_1_INIT { "ftp", HTLoadFile, 0 }
  2766. GLOBALDEF(HTProtocol, HTFTP, _HTFILE_C_1_INIT);
  2767. #define _HTFILE_C_2_INIT { "file", HTLoadFile, HTFileSaveStream }
  2768. GLOBALDEF(HTProtocol, HTFile, _HTFILE_C_2_INIT);
  2769. #else
  2770. GLOBALDEF HTProtocol HTFTP =
  2771. {"ftp", HTLoadFile, 0};
  2772. GLOBALDEF HTProtocol HTFile =
  2773. {"file", HTLoadFile, HTFileSaveStream};
  2774. #endif /* GLOBALDEF_IS_MACRO */