[0001] [0002] [0003] [0004] [0005] [0006] [0007] [0008] [0009] [0010] [0011] [0012] [0013] [0014] [0015] [0016] [0017] [0018] [0019] [0020] [0021] [0022] [0023] [0024] [0025] [0026] [0027] [0028] [0029] [0030] [0031] [0032] [0033] [0034] [0035] [0036] [0037] [0038] [0039] [0040] [0041] [0042] [0043] [0044] [0045] [0046] [0047] [0048] [0049] [0050] [0051] [0052] [0053] [0054] [0055] [0056] [0057] [0058] [0059] [0060] [0061] [0062] [0063] [0064] [0065] [0066] [0067] [0068] [0069] [0070] [0071] [0072] [0073] [0074] [0075] [0076] [0077] [0078] [0079] [0080] [0081] [0082] [0083] [0084] [0085] [0086] [0087] [0088] [0089] [0090] [0091] [0092] [0093] [0094] [0095] [0096] [0097] [0098] [0099] [0100] [0101] [0102] [0103] [0104] [0105] [0106] [0107] [0108] [0109] [0110] [0111] [0112] [0113] [0114] [0115] [0116] [0117] [0118] [0119] [0120] [0121] [0122] [0123] [0124] [0125] [0126] [0127] [0128] [0129] [0130] [0131] [0132] [0133] [0134] [0135] [0136] [0137] [0138] [0139] [0140] [0141] [0142] [0143] [0144] [0145] [0146] [0147] [0148] [0149] [0150] [0151] [0152] [0153] [0154] [0155] [0156] [0157] [0158] [0159] [0160] [0161] [0162] [0163] [0164] [0165] [0166] [0167] [0168] [0169] [0170] [0171] [0172] [0173] [0174] [0175] [0176] [0177] [0178] [0179] [0180] [0181] [0182] [0183] [0184] [0185] [0186] [0187] [0188] [0189] [0190] [0191] [0192] [0193] [0194] [0195] [0196] [0197] [0198] [0199] [0200] [0201] [0202] [0203] [0204] [0205] [0206] [0207] [0208] [0209] [0210] [0211] [0212] [0213] [0214] [0215] [0216] [0217] [0218] [0219] [0220] [0221] [0222] [0223] [0224] [0225] [0226] [0227] [0228] [0229] [0230] [0231] [0232] [0233] [0234] [0235] [0236] [0237] [0238] [0239] [0240] [0241] [0242] [0243] [0244] [0245] [0246] [0247] [0248] [0249] [0250] [0251] [0252] [0253] [0254] [0255] [0256] [0257] [0258] [0259] [0260] [0261] [0262] [0263] [0264] [0265] [0266] [0267] [0268] [0269] [0270] [0271] [0272] [0273] [0274] [0275] [0276] [0277] [0278] [0279] [0280] [0281] [0282] [0283] [0284] [0285] [0286] [0287] [0288] [0289] [0290] [0291] [0292] [0293] [0294] [0295] [0296] [0297] [0298] [0299] [0300] [0301] [0302] [0303] [0304] [0305] [0306] [0307] [0308] [0309] [0310] [0311] [0312] [0313] [0314] [0315] [0316] [0317] [0318] [0319] [0320] [0321] [0322] [0323] [0324] [0325] [0326] [0327] [0328] [0329] [0330] [0331] [0332] [0333] [0334] [0335] [0336] [0337] [0338] [0339] [0340] [0341] [0342] [0343] [0344] [0345] [0346] [0347] [0348] [0349] [0350] [0351] [0352] [0353] [0354] [0355] [0356] [0357] [0358] [0359] [0360] [0361] [0362] [0363] [0364] [0365] [0366] [0367] [0368] [0369] [0370] [0371] [0372] [0373] [0374] [0375] [0376] [0377] [0378] [0379] [0380] [0381] [0382] [0383] [0384] [0385] [0386] [0387] [0388] [0389] [0390] [0391] [0392] [0393] [0394] [0395] [0396] [0397] [0398] [0399] [0400] [0401] [0402] [0403] [0404] [0405] [0406] [0407] [0408] [0409] [0410] [0411] [0412] [0413] [0414] [0415] [0416] [0417] [0418] [0419] [0420] [0421] [0422] [0423] [0424] [0425] [0426] [0427] [0428] [0429] [0430] [0431] [0432] [0433] [0434] [0435] [0436] [0437] [0438] [0439] [0440] [0441] [0442] [0443] [0444] [0445] [0446] [0447] [0448] [0449] [0450] [0451] [0452] [0453] [0454] [0455] [0456] [0457] [0458] [0459] [0460] [0461] [0462] [0463] [0464] [0465] [0466] [0467] [0468] [0469] [0470] [0471] [0472] [0473] [0474] [0475] [0476] [0477] [0478] [0479] [0480] [0481] [0482] [0483] [0484] [0485] [0486] [0487] [0488] [0489] [0490] [0491] [0492] [0493] [0494] [0495] [0496] [0497] [0498] [0499] [0500] [0501] [0502] [0503] [0504] [0505] [0506] [0507] [0508] [0509] [0510] [0511] [0512] [0513] [0514] [0515] [0516] [0517] [0518] [0519] [0520] [0521] [0522] [0523] [0524] [0525] [0526] [0527] [0528] [0529] [0530] [0531] [0532] [0533] [0534] [0535] [0536] [0537] [0538] [0539] [0540] [0541] [0542] [0543] [0544] [0545] [0546] [0547] [0548] [0549] [0550] [0551] [0552] [0553] [0554] [0555] [0556] [0557] [0558] [0559] [0560] [0561] [0562] [0563] [0564] [0565] [0566] [0567] [0568] [0569] [0570] [0571] [0572] [0573] [0574] [0575] [0576] [0577] [0578] [0579] [0580] [0581] [0582] [0583] [0584] [0585] [0586] [0587] [0588] [0589] [0590] [0591] [0592] [0593] [0594] [0595] [0596] [0597] [0598] [0599] [0600] [0601] [0602] [0603] [0604] [0605] [0606] [0607] [0608] [0609] [0610] [0611] [0612] [0613] [0614] [0615] [0616] [0617] [0618] [0619] [0620] [0621] [0622] [0623] [0624] [0625] [0626] [0627] [0628] [0629] [0630] [0631] [0632] [0633] [0634] [0635] [0636] [0637] [0638] [0639] [0640] [0641] [0642] [0643] [0644] [0645] [0646] [0647] [0648] [0649] [0650] [0651] [0652] [0653] [0654] [0655] [0656] [0657] [0658] [0659] [0660] [0661] [0662] [0663] [0664] [0665] [0666] [0667] [0668] [0669] [0670] [0671] [0672] [0673] [0674] [0675] [0676] [0677] [0678] [0679] [0680] [0681] [0682] [0683] [0684] [0685] [0686] [0687] [0688] [0689] [0690] [0691] [0692] [0693] [0694] [0695] [0696] [0697] [0698] [0699] [0700] [0701] [0702] [0703] [0704] [0705] [0706] [0707] [0708] [0709] [0710] [0711] [0712] [0713] [0714] [0715] [0716] [0717] [0718] [0719] [0720] [0721] [0722] [0723] [0724] [0725]
/*****************************************************************************/ /* Descr.c This module implements a full multi-threaded, AST-driven, asynchronous description generator for a file. This is not a full task in the sense of a file transfer. This module merely determines a file description. For an HTML file this is by looking for the contents of a <title></title> or <h2></h2> tag pair. For a plain text file, the first non-blank line. If no internal description can be determined the buffer is made an empty string. This module never returns a valid status and ALWAYS calls the supplied next task (AST) function. This should check for a generated error message to determine is there were any problems. VERSION HISTORY --------------- 06-OCT-2010 MGD DescriptionError() !&S to %X!8XL 05-OCT-2002 MGD refine VMS security profile usage 27-APR-2002 MGD make SYSPRV enabled ASTs asynchronous 04-AUG-2001 MGD support module WATCHing 02-JAN-2000 MGD no significant modifications for ODS-5 (no NAM block) 20-NOV-1999 MGD increase buffer size to 2048 (in part to allow for longer "lines", also to accomodate fixed, 512 byte, FTPed records). 19-SEP-1998 MGD improve granularity of file open, connect, close 25-OCT-1997 MGD DescriptionEscape() now includes only printable characters 17-AUG-1997 MGD message database, SYSUAF-authenticated users security-profile 01-FEB-1997 MGD HTTPd version 4 23-MAY-1996 MGD functionality generalized, moved from directory module */ /*****************************************************************************/ #ifdef WASD_VMS_V7 #undef _VMS__V6__SOURCE #define _VMS__V6__SOURCE #undef __VMS_VER #define __VMS_VER 70000000 #undef __CRTL_VER #define __CRTL_VER 70000000 #endif /* standard C header files */ #include <ctype.h> #include <stdio.h> #include <string.h> /* VMS related header files */ #include <atrdef.h> #include <descrip.h> #include <dvidef.h> #include <fibdef.h> #include <iodef.h> #include <rmsdef.h> #include <rms.h> #include <ssdef.h> #include <stsdef.h> /* application related header files */ #include "wasd.h" #define WASD_MODULE "DESCR" /********************/ /* external storage */ /********************/ extern int ToLowerCase[], ToUpperCase[]; extern char SoftwareID[]; extern CONFIG_STRUCT Config; extern MSG_STRUCT Msgs; extern WATCH_STRUCT Watch; /*****************************************************************************/ /* */ Description ( REQUEST_STRUCT *rqptr, REQUEST_AST NextTaskFunction, char *FileName, char *DescriptionBuffer, int SizeOfDescriptionBuffer, int ContentTypes ) { int status; char *cptr, *sptr, *zptr; DESCR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD__OTHER)) WatchThis (WATCHITM(rqptr), WATCH_MOD__OTHER, "Description() !&A !AZ", NextTaskFunction, FileName); if (ERROR_REPORTED (rqptr)) { /* previous error, cause threaded processing to unravel */ SysDclAst (NextTaskFunction, rqptr); return; } /* set up the task structure (possibly multiple serially) */ if (rqptr->DescrTaskPtr) { tkptr = rqptr->DescrTaskPtr; memset (tkptr, 0, sizeof(DESCR_TASK)); } else { rqptr->DescrTaskPtr = tkptr = (DESCR_TASK*) VmGetHeap (rqptr, sizeof(DESCR_TASK)); } tkptr->NextTaskFunction = NextTaskFunction; /* setup using the calling function's buffer space */ *(tkptr->DescriptionBufferPtr = DescriptionBuffer) = '\0'; tkptr->SizeOfDescriptionBuffer = SizeOfDescriptionBuffer; /* indicate no description could be generated */ tkptr->DescriptionBufferPtr[0] = DESCRIPTION_IMPOSSIBLE; cptr = FileName; zptr = (sptr = tkptr->FileName) + sizeof(tkptr->FileName); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); DescriptionEnd (rqptr); return; } *sptr = '\0'; tkptr->FileNameLength = sptr - tkptr->FileName; /***************/ /* description */ /***************/ /* using the pointer from above find the file type */ while (sptr > tkptr->FileName && *sptr != '.') sptr--; cptr = ConfigContentType (NULL, sptr); if (TOLO(cptr[0]) == 't' && ConfigSameContentType (cptr, "text/", 5)) { if ((ContentTypes & DESCRIPTION_TEXT_HTML || ContentTypes & DESCRIPTION_ALL) && ConfigSameContentType (cptr, "text/html", -1)) { tkptr->TextHtmlFile = true; DescriptionOpen (rqptr); return; } else if ((ContentTypes & DESCRIPTION_TEXT_PLAIN || ContentTypes & DESCRIPTION_ALL) && ConfigSameContentType (cptr, "text/plain", -1)) { tkptr->TextHtmlFile = false; DescriptionOpen (rqptr); return; } } /* declare the next task */ SysDclAst (tkptr->NextTaskFunction, rqptr); } /*****************************************************************************/ /* */ DescriptionEnd (REQUEST_STRUCT *rqptr) { int status; DESCR_TASK *tkptr; /*********/ /* begin */ /*********/ /* retrieve the pointer to the task structure */ tkptr = rqptr->DescrTaskPtr; if (WATCHMOD (rqptr, WATCH_MOD__OTHER)) WatchThis (WATCHITM(rqptr), WATCH_MOD__OTHER, "DescriptionEnd() !&F !AZ", &DescriptionEnd, tkptr->DescriptionBufferPtr); if (tkptr->FileFab.fab$w_ifi) { tkptr->FileFab.fab$l_fop |= FAB$M_ASY; sys$close (&tkptr->FileFab, &DescriptionCloseAst, &DescriptionCloseAst); } else SysDclAst (tkptr->NextTaskFunction, rqptr); } /*****************************************************************************/ /* AST delivered after asynchronous close in DescriptionEnd(). */ DescriptionCloseAst (struct FAB *FabPtr) { /*********/ /* begin */ /*********/ if (WATCH_MOD) { REQUEST_STRUCT *rqptr; rqptr = FabPtr->fab$l_ctx; if (WATCHMOD (rqptr, WATCH_MOD__OTHER)) WatchThis (WATCHITM(rqptr), WATCH_MOD__OTHER, "DescriptionCloseAst() !&F sts!&S stv:!&S", &DescriptionCloseAst, FabPtr->fab$l_sts, FabPtr->fab$l_stv); } DescriptionEnd (FabPtr->fab$l_ctx); } /*****************************************************************************/ /* */ DescriptionOpen (REQUEST_STRUCT *rqptr) { int status; DESCR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD__OTHER)) WatchThis (WATCHITM(rqptr), WATCH_MOD__OTHER, "DescriptionOpen() !&F !AZ !UL", &DescriptionOpen, rqptr->DescrTaskPtr->FileName, rqptr->DescrTaskPtr->TextHtmlFile); tkptr = rqptr->DescrTaskPtr; tkptr->FileFab = cc$rms_fab; tkptr->FileFab.fab$l_ctx = rqptr; tkptr->FileFab.fab$b_fac = FAB$M_GET; tkptr->FileFab.fab$l_fna = tkptr->FileName; tkptr->FileFab.fab$b_fns = tkptr->FileNameLength; tkptr->FileFab.fab$b_shr = FAB$M_SHRGET; AuthAccessEnable (rqptr, tkptr->FileName, AUTH_ACCESS_READ); tkptr->FileFab.fab$l_fop |= FAB$M_ASY; sys$open (&tkptr->FileFab, &DescriptionOpenAst, &DescriptionOpenAst); AuthAccessEnable (rqptr, 0, 0); } /*****************************************************************************/ /* AST called from DescriptionOpen() when asynchronous open completes. Initiate an asynchronous RAB connect. */ DescriptionOpenAst (struct FAB *FabPtr) { int status, MultiBlockCount; REQUEST_STRUCT *rqptr; DESCR_TASK *tkptr; /*********/ /* begin */ /*********/ rqptr = FabPtr->fab$l_ctx; if (WATCHMOD (rqptr, WATCH_MOD__OTHER)) WatchThis (WATCHITM(rqptr), WATCH_MOD__OTHER, "DescriptionOpenAst() !&F sts:!&S stv:!&S", &DescriptionOpenAst, FabPtr->fab$l_sts, FabPtr->fab$l_stv); #if WATCH_MOD HttpdCheckPriv (FI_LI); #endif /* WATCH_MOD */ tkptr = rqptr->DescrTaskPtr; if (VMSnok (status = FabPtr->fab$l_sts)) { DescriptionError (rqptr, status, __LINE__); DescriptionEnd (rqptr); return; } tkptr->FileRab = cc$rms_rab; tkptr->FileRab.rab$l_ctx = rqptr; tkptr->FileRab.rab$l_fab = &tkptr->FileFab; /* 2 buffers and read ahead performance option */ tkptr->FileRab.rab$b_mbf = 2; tkptr->FileRab.rab$l_rop = RAB$M_RAH | RAB$M_ASY; tkptr->FileRab.rab$l_ubf = tkptr->ReadBuffer; tkptr->FileRab.rab$w_usz = sizeof(tkptr->ReadBuffer)-1; sys$connect (&tkptr->FileRab, &DescriptionConnectAst, &DescriptionConnectAst); } /*****************************************************************************/ /* AST called from FileOpenAst() when asynchronous RAB connect completes. Initiate stream-LF file conversion if the file meets requirements. If suitable for caching then initiate a cache load and begin reading the file contents. */ DescriptionConnectAst (struct RAB *RabPtr) { int status; REQUEST_STRUCT *rqptr; DESCR_TASK *tkptr; /*********/ /* begin */ /*********/ rqptr = RabPtr->rab$l_ctx; if (WATCHMOD (rqptr, WATCH_MOD__OTHER)) WatchThis (WATCHITM(rqptr), WATCH_MOD__OTHER, "DescriptionConnectAst() !&F sts:!&S stv:!&S", &DescriptionConnectAst, RabPtr->rab$l_sts, RabPtr->rab$l_stv); tkptr = rqptr->DescrTaskPtr; if (VMSnok (status = RabPtr->rab$l_sts)) { DescriptionError (rqptr, status, __LINE__); DescriptionEnd (rqptr); return; } *(tkptr->DescriptionPtr = tkptr->DescriptionBufferPtr) = '\0'; tkptr->DescriptionRetrieved = false; tkptr->DescriptionLineCount = 0; /* queue up a read of the first record in the file */ if (tkptr->TextHtmlFile) sys$get (&tkptr->FileRab, &DescriptionHtmlRecord, &DescriptionHtmlRecord); else sys$get (&tkptr->FileRab, &DescriptionPlainRecord, &DescriptionPlainRecord); } /*****************************************************************************/ /* This is an AST completion routine called each time sys$get() completes. It returns with the next record, end-of-file, or some other error. Examine the record looking for text comprising the first of either the <title></title> element or a heading element (e.g. <h2></h2>), retrieving this and using it as the file description. */ DescriptionHtmlRecord (struct RAB *RabPtr) { int status; char *dptr, *rptr, *zptr; REQUEST_STRUCT *rqptr; DESCR_TASK *tkptr; /*********/ /* begin */ /*********/ rqptr = RabPtr->rab$l_ctx; if (WATCHMOD (rqptr, WATCH_MOD__OTHER)) WatchThis (WATCHITM(rqptr), WATCH_MOD__OTHER, "DescriptionHtmlRecord() !&F sts:!&S stv:!&S !UL", &DescriptionHtmlRecord, RabPtr->rab$l_sts, RabPtr->rab$l_stv, RabPtr->rab$w_rsz); tkptr = rqptr->DescrTaskPtr; if (VMSnok (tkptr->FileRab.rab$l_sts)) { if (tkptr->FileRab.rab$l_sts == RMS$_EOF) { /***************/ /* end-of-file */ /***************/ DescriptionEnd (rqptr); return; } /**********************/ /* error reading file */ /**********************/ DescriptionError (rqptr, tkptr->FileRab.rab$l_sts, __LINE__); DescriptionEnd (rqptr); return; } tkptr->DescriptionLineCount++; tkptr->FileRab.rab$l_ubf[tkptr->FileRab.rab$w_rsz] = '\0'; if (WATCHMOD (rqptr, WATCH_MOD__OTHER)) WatchDataDump (tkptr->FileRab.rab$l_ubf, tkptr->FileRab.rab$w_rsz); /****************************************/ /* look for the <title> or <Hn> element */ /****************************************/ /* 'zptr' points at the last character of the description storage. It prevents non-closed <title> or <Hn> structures from running off the end of the storage area. */ dptr = tkptr->DescriptionPtr; zptr = tkptr->DescriptionBufferPtr + tkptr->SizeOfDescriptionBuffer - 1; /* Add a space for any record boundary occuring in the title, except if it's a leading space (i.e. first after the leading quote). */ if (tkptr->DescriptionInside && dptr > tkptr->DescriptionBufferPtr+1 && dptr < zptr) *dptr++ = ' '; for (rptr = tkptr->FileRab.rab$l_ubf; *rptr; rptr++) { if (*rptr == '<') { tkptr->DescriptionOpeningTagCount++; if (TOUP(rptr[1]) == 'T' && strsame (rptr+2, "ITLE>", 5)) { tkptr->DescriptionInside = true; rptr += 6; tkptr->DescriptionClosingTagCount++; continue; } if (TOUP(rptr[1]) == 'H' && isdigit(rptr[2]) && rptr[3] == '>') { tkptr->DescriptionInside = true; rptr += 3; tkptr->DescriptionClosingTagCount++; continue; } if (rptr[1] == '/') { if (TOUP(rptr[2]) == 'T' && strsame (rptr+3, "ITLE>", 5)) { tkptr->DescriptionInside = false; tkptr->DescriptionRetrieved = true; rptr += 7; tkptr->DescriptionClosingTagCount++; /* suppress any trailing white-space */ if (dptr > tkptr->DescriptionBufferPtr+1) dptr--; while (dptr > tkptr->DescriptionBufferPtr+1 && ISLWS(*dptr)) dptr--; *++dptr = '\0'; continue; } if (TOUP(rptr[2]) == 'H' && isdigit(rptr[3]) && rptr[4] == '>') { tkptr->DescriptionInside = false; tkptr->DescriptionRetrieved = true; rptr += 4; tkptr->DescriptionClosingTagCount++; /* suppress any trailing white-space */ if (dptr > tkptr->DescriptionBufferPtr+1) dptr--; while (dptr > tkptr->DescriptionBufferPtr+1 && ISLWS(*dptr)) dptr--; *++dptr = '\0'; continue; } } } else if (*rptr == '>') { tkptr->DescriptionClosingTagCount++; continue; } /* don't scan the line further if we've found what we're looking for */ if (tkptr->DescriptionRetrieved) break; /* if we're currently inside a tag name (between "<" and ">") */ if (tkptr->DescriptionOpeningTagCount > tkptr->DescriptionClosingTagCount) continue; /* suppress leading white-space */ if (tkptr->DescriptionInside && !(dptr == tkptr->DescriptionBufferPtr && ISLWS(*rptr)) && isprint (*rptr) && dptr < zptr) *dptr++ = *rptr; } /* terminate the title/description */ if (dptr > tkptr->DescriptionBufferPtr) *dptr = '\0'; tkptr->DescriptionPtr = dptr; if (tkptr->DescriptionRetrieved || tkptr->DescriptionLineCount > Config.cfDir.DescriptionLines) { /************************************/ /* title found, or out-of-patience! */ /************************************/ DescriptionEnd (rqptr); return; } else { /*****************/ /* still looking */ /*****************/ /* queue another read, completion AST back to this function again */ sys$get (&tkptr->FileRab, &DescriptionHtmlRecord, &DescriptionHtmlRecord); } } /*****************************************************************************/ /* This is an AST completion routine called each time sys$get() completes. It returns with the next record, end-of-file, or some other error. */ DescriptionPlainRecord (struct RAB *RabPtr) { int status; char *dptr, *rptr, *zptr; REQUEST_STRUCT *rqptr; DESCR_TASK *tkptr; /*********/ /* begin */ /*********/ rqptr = RabPtr->rab$l_ctx; if (WATCHMOD (rqptr, WATCH_MOD__OTHER)) WatchThis (WATCHITM(rqptr), WATCH_MOD__OTHER, "DescriptionPlainRecord() !&F sts:!&S stv:!&S !UL", &DescriptionPlainRecord, RabPtr->rab$l_sts, RabPtr->rab$l_stv, RabPtr->rab$w_rsz); tkptr = rqptr->DescrTaskPtr; if (VMSnok (tkptr->FileRab.rab$l_sts)) { if (tkptr->FileRab.rab$l_sts == RMS$_EOF) { /***************/ /* end-of-file */ /***************/ DescriptionEnd (rqptr); return; } /**********************/ /* error reading file */ /**********************/ { DescriptionError (rqptr, tkptr->FileRab.rab$l_sts, __LINE__); DescriptionEnd (rqptr); return; } } tkptr->DescriptionLineCount++; tkptr->FileRab.rab$l_ubf[tkptr->FileRab.rab$w_rsz] = '\0'; if (WATCHMOD (rqptr, WATCH_MOD__OTHER)) WatchDataDump (tkptr->FileRab.rab$l_ubf, tkptr->FileRab.rab$w_rsz); /************************************/ /* look for first plain-text record */ /************************************/ for (rptr = tkptr->FileRab.rab$l_ubf; *rptr && !isalnum(*rptr); rptr++); if (!isalnum(*rptr)) { if (tkptr->DescriptionLineCount <= Config.cfDir.DescriptionLines) { /* queue another read, completion AST back to this function again */ sys$get (&tkptr->FileRab, &DescriptionPlainRecord, &DescriptionPlainRecord); return; } /********************/ /* out-of-patience! */ /********************/ DescriptionEnd (rqptr); return; } /*******************/ /* get description */ /*******************/ dptr = tkptr->DescriptionBufferPtr; zptr = tkptr->DescriptionBufferPtr + tkptr->SizeOfDescriptionBuffer - 1; while (*rptr && dptr < zptr) *dptr++ = *rptr++; *dptr = '\0'; DescriptionEscape (rqptr); DescriptionEnd (rqptr); } /*****************************************************************************/ /* Make sure we only meaningful and HTML-acceptable characters into the description. */ DescriptionEscape (REQUEST_STRUCT *rqptr) { BOOL Changed; char *cptr, *sptr, *zptr; DESCR_TASK *tkptr; char Buffer [256]; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD__OTHER)) WatchThis (WATCHITM(rqptr), WATCH_MOD__OTHER, "DescriptionEscape()"); /* retrieve the pointer to the task structure */ tkptr = rqptr->DescrTaskPtr; Changed = false; if (tkptr->SizeOfDescriptionBuffer > sizeof(Buffer)) zptr = (sptr = Buffer) + tkptr->SizeOfDescriptionBuffer - 1; else zptr = (sptr = Buffer) + sizeof(Buffer)-1; for (cptr = tkptr->DescriptionBufferPtr; *cptr && sptr+6 < zptr; cptr++) { switch (*cptr) { case '<' : memcpy (sptr, "<", 4); sptr += 4; Changed = true; break; case '>' : memcpy (sptr, ">", 4); sptr += 4; Changed = true; break; case '&' : memcpy (sptr, "&", 5); sptr += 5; Changed = true; break; case '\"' : *sptr++ = '\''; Changed = true; break; default: if (isprint(*cptr)) *sptr++ = *cptr; } } *sptr++ = '\0'; if (Changed) memcpy (tkptr->DescriptionBufferPtr, Buffer, sptr - Buffer); } /*****************************************************************************/ /* Put the hexadecimal VMS status value into the description buffer as an error indication. */ DescriptionError ( REQUEST_STRUCT *rqptr, int StatusValue, int SourceLineNumber ) { static $DESCRIPTOR (ErrorFaoDsc, "<font color=\"#ff0000\">[Error %X!8XL]</font><!!-- !UL -->\0"); static $DESCRIPTOR (BufferDsc, ""); DESCR_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD__OTHER)) WatchThis (WATCHITM(rqptr), WATCH_MOD__OTHER, "DescriptionError() !&S", StatusValue); tkptr = rqptr->DescrTaskPtr; BufferDsc.dsc$a_pointer = tkptr->DescriptionBufferPtr; BufferDsc.dsc$w_length = tkptr->SizeOfDescriptionBuffer; sys$fao (&ErrorFaoDsc, 0, &BufferDsc, StatusValue, SourceLineNumber); } /*****************************************************************************/