~ubuntu-branches/ubuntu/edgy/lynx/edgy

« back to all changes in this revision

Viewing changes to WWW/Library/Implementation/HTVMSUtils.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-09-16 12:14:10 UTC
  • Revision ID: james.westby@ubuntu.com-20040916121410-cz1gu92c4nqfeyrg
Tags: upstream-2.8.5
ImportĀ upstreamĀ versionĀ 2.8.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/* MODULE                                                       HTVMSUtil.c
 
3
**              VMS Utility Routines
 
4
**
 
5
** AUTHORS:
 
6
**      MD      Mark Donszelmann    duns@vxdeop.cern.ch
 
7
**
 
8
** HISTORY:
 
9
**      14 Nov 93  MD   Written
 
10
**
 
11
** BUGS:
 
12
**
 
13
**
 
14
*/
 
15
 
 
16
#include <HTUtils.h>
 
17
#include <HTFormat.h>
 
18
#include <HTStream.h>
 
19
#include <UCDefs.h>
 
20
#include <UCMap.h>
 
21
#include <UCAux.h>
 
22
#include <HTFTP.h>
 
23
#include <HTTCP.h>
 
24
#include <HTVMSUtils.h>
 
25
#include <ssdef.h>
 
26
#include <jpidef.h>
 
27
#include <prvdef.h>
 
28
#include <acldef.h>
 
29
#include <chpdef.h>
 
30
#include <descrip.h>
 
31
#include <lib$routines.h>
 
32
#include <starlet.h>
 
33
#include <rmsdef.h>
 
34
 
 
35
#include <LYGlobalDefs.h>
 
36
#include <LYUtils.h>
 
37
#include <LYLeaks.h>
 
38
#include <LYStrings.h>
 
39
 
 
40
PUBLIC BOOL HTVMSFileVersions = FALSE; /* Include version numbers in listing? */
 
41
 
 
42
typedef struct {
 
43
   unsigned long BufferLength : 16;
 
44
   unsigned long ItemCode : 16;
 
45
   unsigned long BufferAddress : 32;
 
46
   unsigned long ReturnLengthAddress : 32;
 
47
} ItemStruct;
 
48
 
 
49
/* PUBLIC                                                       HTVMS_authSysPrv()
 
50
**              CHECKS IF THIS PROCESS IS AUTHORIZED TO ENABLE SYSPRV
 
51
** ON ENTRY:
 
52
**      No arguments.
 
53
**
 
54
** ON EXIT:
 
55
**      returns YES if SYSPRV is authorized
 
56
*/
 
57
PUBLIC BOOL HTVMS_authSysPrv NOARGS
 
58
{
 
59
unsigned long Result;
 
60
ItemStruct ItemList[2];
 
61
unsigned long Length;
 
62
unsigned long Buffer[2];
 
63
 
 
64
  /* fill Item */
 
65
  ItemList[0].BufferLength = sizeof(Buffer);
 
66
  ItemList[0].BufferAddress = (unsigned long)Buffer;
 
67
  ItemList[0].ReturnLengthAddress = (unsigned long)&Length;
 
68
  ItemList[0].ItemCode = JPI$_AUTHPRIV;
 
69
 
 
70
  /* terminate list */
 
71
  ItemList[1].ItemCode = 0;
 
72
  ItemList[1].BufferLength = 0;
 
73
 
 
74
  /* call system */
 
75
  Result = sys$getjpiw(0, 0, 0, ItemList, 0, 0, 0);
 
76
 
 
77
  if (Result != SS$_NORMAL)
 
78
     return(NO);
 
79
 
 
80
  if (Buffer[0] & PRV$M_SYSPRV)
 
81
     return(YES);
 
82
 
 
83
  return(NO);
 
84
}
 
85
 
 
86
 
 
87
 
 
88
/* PUBLIC                                                       HTVMS_enableSysPrv()
 
89
**              ENABLES SYSPRV
 
90
** ON ENTRY:
 
91
**      No arguments.
 
92
**
 
93
** ON EXIT:
 
94
**
 
95
*/
 
96
PUBLIC void HTVMS_enableSysPrv NOARGS
 
97
{
 
98
unsigned long Result;
 
99
unsigned long Prv[2], PreviousPrv[2];
 
100
 
 
101
   Prv[0] = PRV$M_SYSPRV;
 
102
   Prv[1] = 0;
 
103
   Result = sys$setprv(1,&Prv,0,&PreviousPrv);
 
104
 
 
105
   if (Result == SS$_NORMAL) {
 
106
       if (!(PreviousPrv[0] & PRV$M_SYSPRV)) {
 
107
           CTRACE((tfp, "HTVMS_enableSysPrv: Enabled SYSPRV\n"));
 
108
       }
 
109
   }
 
110
}
 
111
 
 
112
 
 
113
 
 
114
/* PUBLIC                                                       HTVMS_disableSysPrv()
 
115
**              DISABLES SYSPRV
 
116
** ON ENTRY:
 
117
**      No arguments.
 
118
**
 
119
** ON EXIT:
 
120
**
 
121
*/
 
122
PUBLIC void HTVMS_disableSysPrv NOARGS
 
123
{
 
124
unsigned long Result;
 
125
unsigned long Prv[2], PreviousPrv[2];
 
126
 
 
127
   Prv[0] = PRV$M_SYSPRV;
 
128
   Prv[1] = 0;
 
129
   Result = sys$setprv(0,&Prv,0,&PreviousPrv);
 
130
 
 
131
   if (Result == SS$_NORMAL) {
 
132
       if (PreviousPrv[0] & PRV$M_SYSPRV) {
 
133
           CTRACE((tfp, "HTVMS_disableSysPrv: Disabled SYSPRV\n"));
 
134
       }
 
135
   }
 
136
}
 
137
 
 
138
 
 
139
 
 
140
/* PUBLIC                                                       HTVMS_checkAccess()
 
141
**              CHECKS ACCESS TO FILE FOR CERTAIN USER
 
142
** ON ENTRY:
 
143
**      FileName        The file to be accessed
 
144
**      UserName        Name of the user to check access for.
 
145
**                      User nobody, represented by "" is given NO for an answer
 
146
**      Method          Name of the method to be chceked
 
147
**
 
148
** ON EXIT:
 
149
**      returns YES if access is allowed
 
150
**
 
151
*/
 
152
PUBLIC BOOL HTVMS_checkAccess ARGS3(
 
153
        CONST char *, FileName,
 
154
        CONST char *, UserName,
 
155
        CONST char *, Method)
 
156
{
 
157
unsigned long Result;
 
158
ItemStruct ItemList[2];
 
159
unsigned long Length;
 
160
unsigned long Buffer;
 
161
unsigned long ObjType;
 
162
 
 
163
char *VmsName;
 
164
 
 
165
struct dsc$descriptor_s FileNameDesc;
 
166
struct dsc$descriptor_s UserNameDesc;
 
167
 
 
168
char *colon;
 
169
 
 
170
   /* user nobody should access as from account under which server is running */
 
171
   if (0 == strcmp(UserName,""))
 
172
      return(NO);
 
173
 
 
174
   /* check Filename and convert */
 
175
   colon = strchr(FileName,':');
 
176
   if (colon)
 
177
      VmsName = HTVMS_name("",colon+1);
 
178
   else
 
179
      VmsName = HTVMS_name("",FileName);
 
180
 
 
181
   /* check for GET */
 
182
   if (0 == strcmp(Method,"GET"))
 
183
   {
 
184
     /* fill Item */
 
185
     ItemList[0].BufferLength = sizeof(Buffer);
 
186
     ItemList[0].BufferAddress = (unsigned long)&Buffer;
 
187
     ItemList[0].ReturnLengthAddress = (unsigned long)&Length;
 
188
     ItemList[0].ItemCode = CHP$_FLAGS;
 
189
 
 
190
     /* terminate list */
 
191
     ItemList[1].ItemCode = 0;
 
192
     ItemList[1].BufferLength = 0;
 
193
 
 
194
     /* fill input */
 
195
     ObjType = ACL$C_FILE;
 
196
     Buffer = CHP$M_READ;
 
197
     UserNameDesc.dsc$w_length = strlen(UserName);
 
198
     UserNameDesc.dsc$b_dtype = DSC$K_DTYPE_T;
 
199
     UserNameDesc.dsc$b_class = DSC$K_CLASS_S;
 
200
     UserNameDesc.dsc$a_pointer = (char *)UserName;
 
201
     FileNameDesc.dsc$w_length = strlen(VmsName);
 
202
     FileNameDesc.dsc$b_dtype = DSC$K_DTYPE_T;
 
203
     FileNameDesc.dsc$b_class = DSC$K_CLASS_S;
 
204
     FileNameDesc.dsc$a_pointer = VmsName;
 
205
 
 
206
     /* call system */
 
207
     Result = sys$check_access(&ObjType,&FileNameDesc,&UserNameDesc,ItemList);
 
208
 
 
209
     if (Result == SS$_NORMAL)
 
210
        return(YES);
 
211
     else
 
212
        return(NO);
 
213
   }
 
214
 
 
215
   return(NO);
 
216
}
 
217
 
 
218
 
 
219
 
 
220
/* PUBLIC                                                       HTVMS_wwwName()
 
221
**              CONVERTS VMS Name into WWW Name
 
222
** ON ENTRY:
 
223
**      vmsname         VMS file specification (NO NODE)
 
224
**
 
225
** ON EXIT:
 
226
**      returns         www file specification
 
227
**
 
228
** EXAMPLES:
 
229
**      vmsname                         wwwname
 
230
**      DISK$USER                       disk$user
 
231
**      DISK$USER:                      /disk$user/
 
232
**      DISK$USER:[DUNS]                /disk$user/duns
 
233
**      DISK$USER:[DUNS.ECHO]           /disk$user/duns/echo
 
234
**      [DUNS]                          duns
 
235
**      [DUNS.ECHO]                     duns/echo
 
236
**      [DUNS.ECHO.-.TRANS]             duns/echo/../trans
 
237
**      [DUNS.ECHO.--.TRANS]            duns/echo/../../trans
 
238
**      [.DUNS]                         duns
 
239
**      [.DUNS.ECHO]                    duns/echo
 
240
**      [.DUNS.ECHO]TEST.COM            duns/echo/test.com
 
241
**      TEST.COM                        test.com
 
242
**
 
243
**
 
244
*/
 
245
PUBLIC char * HTVMS_wwwName ARGS1(
 
246
        CONST char *,   vmsname)
 
247
{
 
248
static char wwwname[LY_MAXPATH];
 
249
CONST char *src;
 
250
char *dst;
 
251
int dir;
 
252
   dst = wwwname;
 
253
   src = vmsname;
 
254
   dir = 0;
 
255
   if (strchr(src,':')) *(dst++) = '/';
 
256
   for ( ; *src != '\0' ; src++)
 
257
   {
 
258
      switch(*src)
 
259
      {
 
260
         case ':':  *(dst++) = '/'; break;
 
261
         case '-': if (dir)
 
262
                   {
 
263
                      if ((*(src-1)=='[' || *(src-1)=='.' || *(src-1)=='-') &&
 
264
                          (*(src+1)=='.' || *(src+1)=='-'))
 
265
                      {
 
266
                          *(dst++) = '/';
 
267
                          *(dst++) = '.';
 
268
                          *(dst++) = '.';
 
269
                      }
 
270
                      else
 
271
                          *(dst++) = '-';
 
272
                   }
 
273
                   else
 
274
                   {
 
275
                      if (*(src-1) == ']') *(dst++) = '/';
 
276
                      *(dst++) = '-';
 
277
                   }
 
278
                   break;
 
279
         case '.': if (dir)
 
280
                   {
 
281
                      if (*(src-1) != '[') *(dst++) = '/';
 
282
                   }
 
283
                   else
 
284
                   {
 
285
                      if (*(src-1) == ']') *(dst++) = '/';
 
286
                      *(dst++) = '.';
 
287
                   }
 
288
                   break;
 
289
         case '[': dir = 1; break;
 
290
         case ']': dir = 0; break;
 
291
         default:  if (*(src-1) == ']') *(dst++) = '/';
 
292
                   *(dst++) = *src;
 
293
                   break;
 
294
      }
 
295
   }
 
296
   *(dst++) = '\0';
 
297
   return(wwwname);
 
298
}
 
299
 
 
300
 
 
301
/*
 
302
**      The code below is for directory browsing by VMS Curses clients.
 
303
**      It is based on the newer WWWLib's HTDirBrw.c. - Foteos Macrides
 
304
*/
 
305
PUBLIC int HTStat ARGS2(
 
306
        CONST char *, filename,
 
307
        struct stat *, info)
 
308
{
 
309
   /*
 
310
      the following stuff does not work in VMS with a normal stat...
 
311
      -->   /disk$user/duns/www if www is a directory
 
312
                is statted like:        /disk$user/duns/www.dir
 
313
                after a normal stat has failed
 
314
      -->   /disk$user/duns     if duns is a toplevel directory
 
315
                is statted like:        /disk$user/000000/duns.dir
 
316
      -->   /disk$user since disk$user is a device
 
317
                is statted like:        /disk$user/000000/000000.dir
 
318
      -->   /
 
319
                searches all devices, no solution yet...
 
320
      -->   /vxcern!/disk$cr/wwwteam/login.com
 
321
                is not statted but granted with fake information...
 
322
   */
 
323
int Result;
 
324
int Len;
 
325
char *Ptr, *Ptr2;
 
326
static char *Name;
 
327
 
 
328
   /* try normal stat... */
 
329
   Result = stat((char *)filename,info);
 
330
   if (Result == 0)
 
331
      return(Result);
 
332
 
 
333
   /* make local copy */
 
334
   StrAllocCopy(Name,filename);
 
335
 
 
336
   /* failed,so do device search in case root is requested */
 
337
   if (!strcmp(Name,"/"))
 
338
   {  /* root requested */
 
339
      return(-1);
 
340
   }
 
341
 
 
342
   /* failed so this might be a directory, add '.dir' */
 
343
   Len = strlen(Name);
 
344
   if (Name[Len-1] == '/')
 
345
      Name[Len-1] = '\0';
 
346
 
 
347
   /* fail in case of device */
 
348
   Ptr = strchr(Name+1,'/');
 
349
   if ((Ptr == NULL) && (Name[0] == '/'))
 
350
   {  /* device only... */
 
351
      StrAllocCat(Name, "/000000/000000");
 
352
   }
 
353
 
 
354
   if (Ptr != NULL)
 
355
   {  /* correct filename in case of toplevel dir */
 
356
      Ptr2 = strchr(Ptr+1,'/');
 
357
      if ((Ptr2 == NULL) && (Name[0] == '/'))
 
358
      {
 
359
         char End[256];
 
360
         LYstrncpy(End, Ptr, sizeof(End) - 1);
 
361
         *(Ptr+1) = '\0';
 
362
         StrAllocCat(Name, "000000");
 
363
         StrAllocCat(Name, End);
 
364
      }
 
365
   }
 
366
 
 
367
   /* try in case a file on toplevel directory or .DIR was already specified */
 
368
   Result = stat(Name,info);
 
369
   if (Result == 0)
 
370
      return(Result);
 
371
 
 
372
   /* add .DIR and try again */
 
373
   StrAllocCat(Name, ".dir");
 
374
   Result = stat(Name,info);
 
375
   return(Result);
 
376
}
 
377
 
 
378
#ifndef _POSIX_SOURCE
 
379
#define d_ino   d_fileno        /* compatability */
 
380
#ifndef NULL
 
381
#define NULL    0
 
382
#endif
 
383
#endif  /* !_POSIX_SOURCE */
 
384
 
 
385
typedef struct __dirdesc {
 
386
        long    context;        /* context descriptor for LIB$FIND_FILE calls */
 
387
        char    dirname[255+1]; /* keeps the directory name, including *.* */
 
388
        struct dsc$descriptor_s dirname_desc;   /* descriptor of dirname */
 
389
} DIR;
 
390
 
 
391
PRIVATE DIR *HTVMSopendir(char *dirname);
 
392
PRIVATE struct dirent *HTVMSreaddir(DIR *dirp);
 
393
PRIVATE int HTVMSclosedir(DIR *dirp);
 
394
 
 
395
/*** #include <sys_dirent.h> ***/
 
396
/*** "sys_dirent.h" ***/
 
397
struct  dirent {
 
398
        unsigned long   d_fileno;       /* file number of entry */
 
399
        unsigned short  d_namlen;       /* length of string in d_name */
 
400
        char            d_name[255+1];  /* name (up to MAXNAMLEN + 1) */
 
401
};
 
402
 
 
403
#ifndef _POSIX_SOURCE
 
404
/*
 
405
 * It's unlikely to change, but make sure that sizeof d_name above is
 
406
 * at least MAXNAMLEN + 1 (more may be added for padding).
 
407
 */
 
408
#define MAXNAMLEN       255
 
409
/*
 
410
 * The macro DIRSIZ(dp) gives the minimum amount of space required to represent
 
411
 * a directory entry.  For any directory entry dp->d_reclen >= DIRSIZ(dp).
 
412
 * Specific filesystem types may use this macro to construct the value
 
413
 * for d_reclen.
 
414
 */
 
415
#undef  DIRSIZ
 
416
#define DIRSIZ(dp) \
 
417
        (((sizeof(struct dirent) - (MAXNAMLEN+1) + ((dp)->d_namlen+1)) +3) & ~3)
 
418
 
 
419
#endif  /* !_POSIX_SOURCE */
 
420
 
 
421
 
 
422
PRIVATE DIR *HTVMSopendir(char *dirname)
 
423
{
 
424
static DIR dir;
 
425
char *closebracket;
 
426
long status;
 
427
struct dsc$descriptor_s entryname_desc;
 
428
struct dsc$descriptor_s dirname_desc;
 
429
static char *DirEntry;
 
430
char Actual[256];
 
431
char VMSentry[256];
 
432
char UnixEntry[256];
 
433
int index;
 
434
char *dot;
 
435
 
 
436
   /* check if directory exists */
 
437
   /* dirname can look like /disk$user/duns/www/test/multi    */
 
438
   /* or like               /disk$user/duns/www/test/multi/   */
 
439
   /* DirEntry should look like     disk$user:[duns.www.test]multi in both cases */
 
440
   /* dir.dirname should look like  disk$user:[duns.www.test.multi] */
 
441
   sprintf(UnixEntry, "%.*s", sizeof(UnixEntry) - 2, dirname);
 
442
   if (UnixEntry[strlen(UnixEntry)-1] != '/')
 
443
      strcat(UnixEntry,"/");
 
444
 
 
445
   StrAllocCopy(DirEntry, HTVMS_name("",UnixEntry));
 
446
   if (strlen(DirEntry) > sizeof(dir.dirname) - 1)
 
447
      return (NULL);
 
448
   strcpy(dir.dirname, DirEntry);
 
449
   index = strlen(DirEntry) - 1;
 
450
 
 
451
   if (DirEntry[index] == ']')
 
452
      DirEntry[index] = '\0';
 
453
 
 
454
   if ((dot = strrchr(DirEntry,'.')) == NULL)
 
455
   {  /* convert disk$user:[duns] into disk$user:[000000]duns.dir */
 
456
      char *openbr = strrchr(DirEntry,'[');
 
457
      if (!openbr)
 
458
      { /* convert disk$user: into disk$user:[000000]000000.dir */
 
459
         if (strlen(dir.dirname) > sizeof(dir.dirname) - 10)
 
460
            return (NULL);
 
461
         sprintf(dir.dirname, "%.*s[000000]", sizeof(dir.dirname) - 9, DirEntry);
 
462
         StrAllocCat(DirEntry,"[000000]000000.dir");
 
463
      }
 
464
      else
 
465
      {
 
466
         char End[256];
 
467
         strcpy(End,openbr+1);
 
468
         *(openbr+1) = '\0';
 
469
         StrAllocCat(DirEntry,"000000]");
 
470
         StrAllocCat(DirEntry,End);
 
471
         StrAllocCat(DirEntry,".dir");
 
472
      }
 
473
   }
 
474
   else
 
475
   {
 
476
      *dot = ']';
 
477
      StrAllocCat(DirEntry,".dir");
 
478
   }
 
479
   /* lib$find_file needs a fixed-size buffer */
 
480
   LYstrncpy(Actual, DirEntry, sizeof(Actual)-1);
 
481
 
 
482
   dir.context = 0;
 
483
   dirname_desc.dsc$w_length = strlen(Actual);
 
484
   dirname_desc.dsc$b_dtype = DSC$K_DTYPE_T;
 
485
   dirname_desc.dsc$b_class = DSC$K_CLASS_S;
 
486
   dirname_desc.dsc$a_pointer = (char *)&(Actual);
 
487
 
 
488
   /* look for the directory */
 
489
   entryname_desc.dsc$w_length = 255;
 
490
   entryname_desc.dsc$b_dtype = DSC$K_DTYPE_T;
 
491
   entryname_desc.dsc$b_class = DSC$K_CLASS_S;
 
492
   entryname_desc.dsc$a_pointer = VMSentry;
 
493
 
 
494
   status = lib$find_file(&(dirname_desc),
 
495
                          &entryname_desc,
 
496
                          &(dir.context),
 
497
                          0,0,0,0);
 
498
   if (!(status & 0x01))
 
499
   { /* directory not found */
 
500
      return(NULL);
 
501
   }
 
502
 
 
503
   if (strlen(dir.dirname) > sizeof(dir.dirname) - 10)
 
504
       return (NULL);
 
505
   if (HTVMSFileVersions)
 
506
       strcat(dir.dirname,"*.*;*");
 
507
   else
 
508
       strcat(dir.dirname,"*.*");
 
509
   dir.context = 0;
 
510
   dir.dirname_desc.dsc$w_length = strlen(dir.dirname);
 
511
   dir.dirname_desc.dsc$b_dtype = DSC$K_DTYPE_T;
 
512
   dir.dirname_desc.dsc$b_class = DSC$K_CLASS_S;
 
513
   dir.dirname_desc.dsc$a_pointer = (char *)&(dir.dirname);
 
514
   return(&dir);
 
515
}
 
516
 
 
517
PRIVATE struct dirent *HTVMSreaddir(DIR *dirp)
 
518
{
 
519
static struct dirent entry;
 
520
long status;
 
521
struct dsc$descriptor_s entryname_desc;
 
522
char *space, *slash;
 
523
char VMSentry[256];
 
524
char *UnixEntry;
 
525
 
 
526
   entryname_desc.dsc$w_length = 255;
 
527
   entryname_desc.dsc$b_dtype = DSC$K_DTYPE_T;
 
528
   entryname_desc.dsc$b_class = DSC$K_CLASS_S;
 
529
   entryname_desc.dsc$a_pointer = VMSentry;
 
530
 
 
531
   status = lib$find_file(&(dirp->dirname_desc),
 
532
                          &entryname_desc,
 
533
                          &(dirp->context),
 
534
                          0,0,0,0);
 
535
   if (status == RMS$_NMF)
 
536
   { /* no more files */
 
537
      return(NULL);
 
538
   }
 
539
   else
 
540
   { /* ok */
 
541
      if (!(status & 0x01)) return(0);
 
542
      if (HTVMSFileVersions)
 
543
          space = strchr(VMSentry,' ');
 
544
      else
 
545
          space = strchr(VMSentry,';');
 
546
      if (space)
 
547
         *space = '\0';
 
548
 
 
549
      /* convert to unix style... */
 
550
      UnixEntry = HTVMS_wwwName(VMSentry);
 
551
      slash = strrchr(UnixEntry,'/') + 1;
 
552
      strcpy(entry.d_name,slash);
 
553
      entry.d_namlen = strlen(entry.d_name);
 
554
      entry.d_fileno = 1;
 
555
      return(&entry);
 
556
   }
 
557
}
 
558
 
 
559
PRIVATE int HTVMSclosedir(DIR *dirp)
 
560
{
 
561
long status;
 
562
 
 
563
   status = lib$find_file_end(&(dirp->context));
 
564
   if (!(status & 0x01)) exit(status);
 
565
   dirp->context = 0;
 
566
   return(0);
 
567
}
 
568
 
 
569
#include <HTAnchor.h>
 
570
#include <HTParse.h>
 
571
#include <HTBTree.h>
 
572
#include <HTFile.h>     /* For HTFileFormat() */
 
573
#include <HTAlert.h>
 
574
/*
 
575
**  Hypertext object building machinery.
 
576
*/
 
577
#include <HTML.h>
 
578
#define PUTC(c) (*targetClass.put_character)(target, c)
 
579
#define PUTS(s) (*targetClass.put_string)(target, s)
 
580
#define START(e) (*targetClass.start_element)(target, e, 0, 0, -1, 0)
 
581
#define END(e) (*targetClass.end_element)(target, e, 0)
 
582
#define FREE_TARGET (*targetClass._free)(target)
 
583
#define ABORT_TARGET (*targetClass._free)(target)
 
584
struct _HTStructured {
 
585
        CONST HTStructuredClass *       isa;
 
586
        /* ... */
 
587
};
 
588
 
 
589
#define STRUCT_DIRENT struct dirent
 
590
 
 
591
PRIVATE char * months[12] = {
 
592
    "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
 
593
};
 
594
 
 
595
typedef struct _VMSEntryInfo {
 
596
    char *       filename;
 
597
    char *       type;
 
598
    char *       date;
 
599
    unsigned int size;
 
600
    BOOLEAN      display;  /* show this entry? */
 
601
} VMSEntryInfo;
 
602
 
 
603
PRIVATE void free_VMSEntryInfo_contents ARGS1(VMSEntryInfo *,entry_info)
 
604
{
 
605
    if (entry_info) {
 
606
        FREE(entry_info->filename);
 
607
        FREE(entry_info->type);
 
608
        FREE(entry_info->date);
 
609
    }
 
610
   /* dont free the struct */
 
611
}
 
612
 
 
613
PUBLIC int compare_VMSEntryInfo_structs ARGS2(VMSEntryInfo *,entry1,
 
614
                                              VMSEntryInfo *,entry2)
 
615
{
 
616
    int i, status;
 
617
    char date1[16], date2[16], time1[8], time2[8], month[4];
 
618
 
 
619
    switch(HTfileSortMethod)
 
620
      {
 
621
        case FILE_BY_SIZE:
 
622
                        /* both equal or both 0 */
 
623
                        if(entry1->size == entry2->size)
 
624
                            return(strcasecomp(entry1->filename,
 
625
                                               entry2->filename));
 
626
                        else
 
627
                            if(entry1->size > entry2->size)
 
628
                                return(1);
 
629
                            else
 
630
                                return(-1);
 
631
        case FILE_BY_TYPE:
 
632
                        if(entry1->type && entry2->type) {
 
633
                            status = strcasecomp(entry1->type, entry2->type);
 
634
                            if(status)
 
635
                                return(status);
 
636
                            /* else fall to filename comparison */
 
637
                        }
 
638
                        return (strcasecomp(entry1->filename,
 
639
                                            entry2->filename));
 
640
        case FILE_BY_DATE:
 
641
                        if(entry1->date && entry2->date) {
 
642
                            /*
 
643
                            ** Make sure we have the correct length. - FM
 
644
                            */
 
645
                            if (strlen(entry1->date) != 12 ||
 
646
                                strlen(entry2->date) != 12) {
 
647
                                return (strcasecomp(entry1->filename,
 
648
                                                    entry2->filename));
 
649
                            }
 
650
                            /*
 
651
                            ** Set up for sorting in reverse
 
652
                            ** chronological order. - FM
 
653
                            */
 
654
                            if (entry1->date[7] != ' ') {
 
655
                                strcpy(date1, "9999");
 
656
                                strcpy(time1, (char *)&entry1->date[7]);
 
657
                            } else {
 
658
                                strcpy(date1, (char *)&entry1->date[8]);
 
659
                                strcpy(time1, "00:00");
 
660
                            }
 
661
                            strncpy(month, entry1->date, 3);
 
662
                            month[3] = '\0';
 
663
                            for (i = 0; i < 12; i++) {
 
664
                                if (!strcasecomp(month, months[i])) {
 
665
                                    break;
 
666
                                }
 
667
                            }
 
668
                            i++;
 
669
                            sprintf(month, "%02d", i);
 
670
                            strcat(date1, month);
 
671
                            strncat(date1, (char *)&entry1->date[4], 2);
 
672
                            date1[8] = '\0';
 
673
                            if (date1[6] == ' ') {
 
674
                                date1[6] = '0';
 
675
                            }
 
676
                            strcat(date1, time1);
 
677
                            if (entry2->date[7] != ' ') {
 
678
                                strcpy(date2, "9999");
 
679
                                strcpy(time2, (char *)&entry2->date[7]);
 
680
                            } else {
 
681
                                strcpy(date2, (char *)&entry2->date[8]);
 
682
                                strcpy(time2, "00:00");
 
683
                            }
 
684
                            strncpy(month, entry2->date, 3);
 
685
                            month[3] = '\0';
 
686
                            for (i = 0; i < 12; i++) {
 
687
                                if (!strcasecomp(month, months[i])) {
 
688
                                    break;
 
689
                                }
 
690
                            }
 
691
                            i++;
 
692
                            sprintf(month, "%02d", i);
 
693
                            strcat(date2, month);
 
694
                            strncat(date2, (char *)&entry2->date[4], 2);
 
695
                            date2[8] = '\0';
 
696
                            if (date2[6] == ' ') {
 
697
                                date2[6] = '0';
 
698
                            }
 
699
                            strcat(date2, time2);
 
700
                            /*
 
701
                            ** Do the comparison. - FM
 
702
                            */
 
703
                            status = strcasecomp(date2, date1);
 
704
                            if(status)
 
705
                                return(status);
 
706
                            /* else fall to filename comparison */
 
707
                        }
 
708
                        return (strcasecomp(entry1->filename,
 
709
                                            entry2->filename));
 
710
        case FILE_BY_NAME:
 
711
        default:
 
712
                        return (strcmp(entry1->filename,
 
713
                                            entry2->filename));
 
714
      }
 
715
}
 
716
 
 
717
 
 
718
/*                                                      HTVMSBrowseDir()
 
719
**
 
720
**      This function generates a directory listing as an HTML-object
 
721
**      for local file URL's.  It assumes the first two elements of
 
722
**      of the path are a device followed by a directory:
 
723
**
 
724
**              file://localhost/device/directory[/[foo]]
 
725
**
 
726
**      Will not accept 000000 as a directory name.
 
727
**      Will offer links to parent through the top directory, unless
 
728
**      a terminal slash was included in the calling URL.
 
729
**
 
730
**      Returns HT_LOADED on success, HTLoadError() messages on error.
 
731
**
 
732
**      Developed for Lynx by Foteos Macrides (macrides@sci.wfeb.edu).
 
733
*/
 
734
PUBLIC int HTVMSBrowseDir ARGS4(
 
735
        CONST char *,           address,
 
736
        HTParentAnchor *,       anchor,
 
737
        HTFormat,               format_out,
 
738
        HTStream *,             sink
 
739
)
 
740
{
 
741
    HTStructured* target;
 
742
    HTStructuredClass targetClass;
 
743
    char *pathname = HTParse(address, "", PARSE_PATH + PARSE_PUNCTUATION);
 
744
    char *tail = NULL;
 
745
    char *title = NULL;
 
746
    char *header = NULL;
 
747
    char *parent = NULL;
 
748
    char *relative = NULL;
 
749
    char *cp, *cp1;
 
750
    int  pathend, len;
 
751
    DIR *dp;
 
752
    struct stat file_info;
 
753
    time_t NowTime;
 
754
    static char ThisYear[8];
 
755
    VMSEntryInfo *entry_info = 0;
 
756
    char string_buffer[64];
 
757
 
 
758
    HTUnEscape(pathname);
 
759
    CTRACE((tfp,"HTVMSBrowseDir: Browsing `%s\'\n", pathname));
 
760
 
 
761
    /*
 
762
     *  Require at least two elements (presumably a device and directory)
 
763
     *  and disallow the device root (000000 directory).  Symbolic paths
 
764
     *  (e.g., sys$help) should have been translated and expanded (e.g.,
 
765
     *  to /sys$sysroot/syshlp) before calling this routine.
 
766
     */
 
767
    if (((*pathname != '/') ||
 
768
         (cp = strchr(pathname+1, '/')) == NULL ||
 
769
         *(cp + 1) == '\0' ||
 
770
         0 == strncmp((cp + 1), "000000", 6)) ||
 
771
        (dp = HTVMSopendir(pathname)) == NULL) {
 
772
        FREE(pathname);
 
773
        return HTLoadError(sink, 403, COULD_NOT_ACCESS_DIR);
 
774
    }
 
775
 
 
776
    /*
 
777
     *  Set up the output stream.
 
778
     */
 
779
    _HTProgress (BUILDING_DIR_LIST);
 
780
    if (UCLYhndl_HTFile_for_unspec >= 0) {
 
781
        HTAnchor_setUCInfoStage(anchor,
 
782
                                UCLYhndl_HTFile_for_unspec,
 
783
                                UCT_STAGE_PARSER,
 
784
                                UCT_SETBY_DEFAULT);
 
785
    }
 
786
    target = HTML_new(anchor, format_out, sink);
 
787
    targetClass = *(target->isa);
 
788
 
 
789
    /*
 
790
     *  Set up the offset string of the anchor reference,
 
791
     *  and strings for the title and header.
 
792
     */
 
793
    cp = strrchr(pathname, '/');  /* find lastslash */
 
794
    StrAllocCopy(tail, (cp+1)); /* take slash off the beginning */
 
795
    if (*tail != '\0') {
 
796
        StrAllocCopy(title, tail);
 
797
        *cp = '\0';
 
798
        if ((cp1=strrchr(pathname, '/')) != NULL &&
 
799
            cp1 != pathname &&
 
800
            strncmp((cp1+1), "000000", 6))
 
801
            StrAllocCopy(parent, (cp1+1));
 
802
        *cp = '/';
 
803
    } else {
 
804
        pathname[strlen(pathname)-1] = '\0';
 
805
        cp = strrchr(pathname, '/');
 
806
        StrAllocCopy(title, (cp+1));
 
807
        pathname[strlen(pathname)] = '/';
 
808
    }
 
809
    StrAllocCopy(header, pathname);
 
810
 
 
811
    /*
 
812
     *  Initialize path name for HTStat().
 
813
     */
 
814
    pathend = strlen(pathname);
 
815
    if (*(pathname+pathend-1) != '/') {
 
816
        StrAllocCat(pathname, "/");
 
817
        pathend++;
 
818
    }
 
819
 
 
820
    /*
 
821
     *  Output the title and header.
 
822
     */
 
823
    START(HTML_HTML);
 
824
    PUTC('\n');
 
825
    START(HTML_HEAD);
 
826
    PUTC('\n');
 
827
    HTUnEscape(title);
 
828
    START(HTML_TITLE);
 
829
    PUTS(title);
 
830
    PUTS(" directory");
 
831
    END(HTML_TITLE);
 
832
    PUTC('\n');
 
833
    FREE(title);
 
834
    END(HTML_HEAD);
 
835
    PUTC('\n');
 
836
    START(HTML_BODY);
 
837
    PUTC('\n');
 
838
    HTUnEscape(header);
 
839
    START(HTML_H1);
 
840
    PUTS(header);
 
841
    END(HTML_H1);
 
842
    PUTC('\n');
 
843
    if (HTDirReadme == HT_DIR_README_TOP) {
 
844
        FILE * fp;
 
845
        if (header[strlen(header)-1] != '/')
 
846
            StrAllocCat(header, "/");
 
847
        StrAllocCat(header, HT_DIR_README_FILE);
 
848
        if ((fp = fopen(header,  "r")) != NULL) {
 
849
            START(HTML_PRE);
 
850
            for(;;) {
 
851
                char c = fgetc(fp);
 
852
                if (c == (char)EOF)
 
853
                    break;
 
854
#ifdef NOTDEFINED
 
855
                switch (c) {
 
856
                    case '&':
 
857
                    case '<':
 
858
                    case '>':
 
859
                        PUTC('&');
 
860
                        PUTC('#');
 
861
                        PUTC((char)(c / 10));
 
862
                        PUTC((char) (c % 10));
 
863
                        PUTC(';');
 
864
                        break;
 
865
                    default:
 
866
                        PUTC(c);
 
867
                }
 
868
#else
 
869
                PUTC(c);
 
870
#endif /* NOTDEFINED */
 
871
            }
 
872
            END(HTML_PRE);
 
873
            fclose(fp);
 
874
        }
 
875
    }
 
876
    FREE(header);
 
877
    if (parent) {
 
878
        HTSprintf0(&relative, "%s/..", tail);
 
879
        HTStartAnchor(target, "", relative);
 
880
        PUTS("Up to ");
 
881
        HTUnEscape(parent);
 
882
        PUTS(parent);
 
883
        END(HTML_A);
 
884
        START(HTML_P);
 
885
        PUTC('\n');
 
886
        FREE(relative);
 
887
        FREE(parent);
 
888
    }
 
889
 
 
890
    /*
 
891
     *  Set up the date comparison.
 
892
     */
 
893
    NowTime = time(NULL);
 
894
    strcpy(ThisYear, (char *)ctime(&NowTime)+20);
 
895
    ThisYear[4] = '\0';
 
896
 
 
897
    /*
 
898
     * Now, generate the Btree and put it out to the output stream.
 
899
     */
 
900
    {
 
901
        char dottest = 2;       /* To avoid two strcmp() each time */
 
902
        STRUCT_DIRENT *dirbuf;
 
903
        HTBTree *bt;
 
904
 
 
905
        /* Set up sort key and initialize BTree */
 
906
        bt = HTBTree_new((HTComparer) compare_VMSEntryInfo_structs);
 
907
 
 
908
        /* Build tree */
 
909
        while ((dirbuf = HTVMSreaddir(dp))) {
 
910
            HTAtom *encoding = NULL;
 
911
            HTFormat format;
 
912
 
 
913
            /* Skip if not used */
 
914
            if (!dirbuf->d_ino) {
 
915
                continue;
 
916
            }
 
917
 
 
918
            /* Current and parent directories are never shown in list */
 
919
            if (dottest && (!strcmp(dirbuf->d_name, ".") ||
 
920
                            !strcmp(dirbuf->d_name, ".."))) {
 
921
                dottest--;
 
922
                continue;
 
923
            }
 
924
 
 
925
            /* Don't show the selective enabling file
 
926
             * unless version numbers are included */
 
927
            if (!strcasecomp(dirbuf->d_name, HT_DIR_ENABLE_FILE)) {
 
928
                continue;
 
929
            }
 
930
 
 
931
            /* Skip files beginning with a dot? */
 
932
            if ((no_dotfiles || !show_dotfiles) && *dirbuf->d_name == '.') {
 
933
                continue;
 
934
            }
 
935
 
 
936
            /* OK, make an lstat() and get a key ready. */
 
937
            *(pathname+pathend) = '\0';
 
938
            StrAllocCat(pathname, dirbuf->d_name);
 
939
            if (HTStat(pathname, &file_info)) {
 
940
                /* for VMS the failure here means the file is not readable...
 
941
                   we however continue to browse through the directory... */
 
942
                continue;
 
943
            }
 
944
            entry_info = (VMSEntryInfo *)malloc(sizeof(VMSEntryInfo));
 
945
            if (entry_info == NULL)
 
946
                outofmem(__FILE__, "HTVMSBrowseDir");
 
947
            entry_info->type = 0;
 
948
            entry_info->size = 0;
 
949
            entry_info->date = 0;
 
950
            entry_info->filename = 0;
 
951
            entry_info->display = TRUE;
 
952
 
 
953
            /* Get the type */
 
954
            format = HTFileFormat(dirbuf->d_name, &encoding,
 
955
                                  (CONST char **)&cp);
 
956
            if (!cp) {
 
957
                if(!strncmp(HTAtom_name(format), "application",11))
 
958
                {
 
959
                    cp = HTAtom_name(format) + 12;
 
960
                    if(!strncmp(cp,"x-", 2))
 
961
                        cp += 2;
 
962
                }
 
963
                else
 
964
                    cp = HTAtom_name(format);
 
965
            }
 
966
            StrAllocCopy(entry_info->type, cp);
 
967
 
 
968
            StrAllocCopy(entry_info->filename, dirbuf->d_name);
 
969
            if (S_ISDIR(file_info.st_mode)) {
 
970
                /* strip .DIR part... */
 
971
                char *dot;
 
972
                dot = strstr(entry_info->filename, ".DIR");
 
973
                if (dot)
 
974
                   *dot = '\0';
 
975
                LYLowerCase(entry_info->filename);
 
976
                StrAllocCopy(entry_info->type, "Directory");
 
977
            } else {
 
978
                if ((cp = strstr(entry_info->filename, "READ")) == NULL) {
 
979
                    cp = entry_info->filename;
 
980
                } else {
 
981
                    cp += 4;
 
982
                    if (!strncmp(cp, "ME", 2)) {
 
983
                        cp += 2;
 
984
                        while (cp && *cp && *cp != '.') {
 
985
                            cp++;
 
986
                        }
 
987
                    } else if (!strncmp(cp, ".ME", 3)) {
 
988
                        cp = (entry_info->filename +
 
989
                              strlen(entry_info->filename));
 
990
                    } else {
 
991
                        cp = entry_info->filename;
 
992
                    }
 
993
                }
 
994
                LYLowerCase(cp);
 
995
                if (((len = strlen(entry_info->filename)) > 2) &&
 
996
                    entry_info->filename[len-1] == 'z') {
 
997
                    if (entry_info->filename[len-2] == '.' ||
 
998
                        entry_info->filename[len-2] == '_')
 
999
                        entry_info->filename[len-1] = 'Z';
 
1000
                }
 
1001
            }
 
1002
 
 
1003
            /* Get the date */
 
1004
            {
 
1005
                char *t = (char *)ctime((CONST time_t *)&file_info.st_ctime);
 
1006
                *(t+24) = '\0';
 
1007
 
 
1008
                StrAllocCopy(entry_info->date, (t+4));
 
1009
                *((entry_info->date)+7) = '\0';
 
1010
                if ((atoi((t+19))) < atoi(ThisYear))
 
1011
                    StrAllocCat(entry_info->date,  (t+19));
 
1012
                else {
 
1013
                    StrAllocCat(entry_info->date, (t+11));
 
1014
                    *((entry_info->date)+12) = '\0';
 
1015
                }
 
1016
            }
 
1017
 
 
1018
            /* Get the size */
 
1019
            if (!S_ISDIR(file_info.st_mode))
 
1020
                entry_info->size = (unsigned int)file_info.st_size;
 
1021
            else
 
1022
                entry_info->size = 0;
 
1023
 
 
1024
            /* Now, update the BTree etc. */
 
1025
            if(entry_info->display)
 
1026
              {
 
1027
                 CTRACE((tfp,"Adding file to BTree: %s\n",
 
1028
                                                      entry_info->filename));
 
1029
                 HTBTree_add(bt, entry_info);
 
1030
              }
 
1031
 
 
1032
        } /* End while HTVMSreaddir() */
 
1033
 
 
1034
        FREE(pathname);
 
1035
        HTVMSclosedir(dp);
 
1036
 
 
1037
        START(HTML_PRE);
 
1038
        /*
 
1039
         * Run through the BTree printing out in order
 
1040
         */
 
1041
        {
 
1042
            HTBTElement * ele;
 
1043
            int i;
 
1044
            for (ele = HTBTree_next(bt, NULL);
 
1045
                 ele != NULL;
 
1046
                 ele = HTBTree_next(bt, ele))
 
1047
            {
 
1048
                entry_info = (VMSEntryInfo *)HTBTree_object(ele);
 
1049
 
 
1050
                /* Output the date */
 
1051
                if(entry_info->date)
 
1052
                       {
 
1053
                             PUTS(entry_info->date);
 
1054
                             PUTS("  ");
 
1055
                       }
 
1056
                else
 
1057
                        PUTS("     * ");
 
1058
 
 
1059
                /* Output the type */
 
1060
                if(entry_info->type)
 
1061
                  {
 
1062
                    for(i = 0; entry_info->type[i] != '\0' && i < 15; i++)
 
1063
                        PUTC(entry_info->type[i]);
 
1064
                    for(; i < 17; i++)
 
1065
                        PUTC(' ');
 
1066
 
 
1067
                  }
 
1068
 
 
1069
                /* Output the link for the name */
 
1070
                HTDirEntry(target, tail, entry_info->filename);
 
1071
                PUTS(entry_info->filename);
 
1072
                END(HTML_A);
 
1073
 
 
1074
                /* Output the size */
 
1075
                if(entry_info->size)
 
1076
                  {
 
1077
                          if(entry_info->size < 1024)
 
1078
                              sprintf(string_buffer,"  %d bytes",
 
1079
                                                        entry_info->size);
 
1080
                          else
 
1081
                              sprintf(string_buffer,"  %dKb",
 
1082
                                                        entry_info->size/1024);
 
1083
                          PUTS(string_buffer);
 
1084
                  }
 
1085
 
 
1086
                PUTC('\n'); /* end of this entry */
 
1087
 
 
1088
                free_VMSEntryInfo_contents(entry_info);
 
1089
            }
 
1090
        }
 
1091
 
 
1092
        HTBTreeAndObject_free(bt);
 
1093
 
 
1094
    } /* End of both BTree loops */
 
1095
 
 
1096
    /*
 
1097
     *  Complete the output stream.
 
1098
     */
 
1099
    END(HTML_PRE);
 
1100
    PUTC('\n');
 
1101
    END(HTML_BODY);
 
1102
    PUTC('\n');
 
1103
    END(HTML_HTML);
 
1104
    PUTC('\n');
 
1105
    FREE(tail);
 
1106
    FREE_TARGET;
 
1107
 
 
1108
    return HT_LOADED;
 
1109
 
 
1110
} /* End of directory reading section */
 
1111
 
 
1112
/*
 
1113
 * Remove all versions of the given file.  We assume there are no permissions
 
1114
 * problems, since we do this mainly for removing temporary files.
 
1115
 */
 
1116
int HTVMS_remove(char *filename)
 
1117
{
 
1118
    int code = remove(filename);        /* return the first status code */
 
1119
    while (remove(filename) == 0)
 
1120
        ;
 
1121
    return code;
 
1122
}
 
1123
 
 
1124
/*
 
1125
 * Remove all older versions of the given file.  We may fail to remove some
 
1126
 * version due to permissions -- the loop stops either at that point, or when
 
1127
 * we run out of older versions to remove.
 
1128
 */
 
1129
void HTVMS_purge(char *filename)
 
1130
{
 
1131
    char *older_file = 0;
 
1132
    char *oldest_file = 0;
 
1133
    struct stat sb;
 
1134
 
 
1135
    StrAllocCopy(older_file, filename);
 
1136
    StrAllocCat(older_file, ";-1");
 
1137
 
 
1138
    while (remove(older_file) == 0)
 
1139
        ;
 
1140
    /*
 
1141
     * If we do not have any more older versions, it is safe to rename the
 
1142
     * current file to version #1.
 
1143
     */
 
1144
    if (stat(older_file, &sb) != 0) {
 
1145
        StrAllocCopy(oldest_file, filename);
 
1146
        StrAllocCat(oldest_file, ";1");
 
1147
        rename(older_file, oldest_file);
 
1148
        FREE(oldest_file);
 
1149
    }
 
1150
 
 
1151
    FREE(older_file);
 
1152
}