Newer
Older
16001
16002
16003
16004
16005
16006
16007
16008
16009
16010
16011
16012
16013
16014
16015
16016
16017
16018
16019
16020
16021
16022
16023
16024
16025
16026
16027
16028
16029
16030
16031
16032
16033
16034
16035
16036
16037
16038
16039
16040
16041
16042
16043
16044
16045
16046
16047
16048
16049
16050
16051
16052
16053
16054
16055
16056
16057
16058
16059
16060
16061
16062
16063
16064
16065
16066
16067
16068
16069
16070
16071
16072
16073
16074
16075
16076
16077
16078
16079
16080
16081
16082
16083
16084
16085
16086
16087
16088
16089
16090
16091
16092
16093
16094
16095
16096
16097
16098
16099
16100
16101
16102
16103
16104
16105
16106
16107
16108
16109
16110
16111
16112
16113
16114
16115
16116
16117
16118
16119
16120
}
++fileNum;
});
// If the temporary attachments directory exists, then delete it.
if (file_exists(gFileAttachDir))
deltree(gFileAttachDir);
}
// This function recursively removes a directory and all of its contents. Returns
// whether or not the directory was removed.
//
// Parameters:
// pDir: The directory to remove (with trailing slash).
//
// Return value: Boolean - Whether or not the directory was removed.
function deltree(pDir)
{
if ((pDir == null) || (pDir == undefined))
return false;
if (typeof(pDir) != "string")
return false;
if (pDir.length == 0)
return false;
// Make sure pDir actually specifies a directory.
if (!file_isdir(pDir))
return false;
// Don't wipe out a root directory.
if ((pDir == "/") || (pDir == "\\") || (/:\\$/.test(pDir)) || (/:\/$/.test(pDir)) || (/:$/.test(pDir)))
return false;
// If we're on Windows, then use the "RD /S /Q" command to delete
// the directory. Otherwise, assume *nix and use "rm -rf" to
// delete the directory.
if (deltree.inWindows == undefined)
deltree.inWindows = (/^WIN/.test(system.platform.toUpperCase()));
if (deltree.inWindows)
system.exec("RD " + withoutTrailingSlash(pDir) + " /s /q");
else
system.exec("rm -rf " + withoutTrailingSlash(pDir));
// The directory should be gone, so we should return true. I'd like to verify that the
// directory really is gone, but file_exists() seems to return false for directories,
// even if the directory does exist. So I test to make sure no files are seen in the dir.
return (directory(pDir + "*").length == 0);
/*
// Recursively deleting each file & dir using JavaScript:
var retval = true;
// Open the directory and delete each entry.
var files = directory(pDir + "*");
for (var i = 0; i < files.length; ++i)
{
// If the entry is a directory, then deltree it (Note: The entry
// should have a trailing slash). Otherwise, delete the file.
// If the directory/file couldn't be removed, then break out
// of the loop.
if (file_isdir(files[i]))
{
retval = deltree(files[i]);
if (!retval)
break;
}
else
{
retval = file_remove(files[i]);
if (!retval)
break;
}
}
// Delete the directory specified by pDir.
if (retval)
retval = rmdir(pDir);
return retval;
*/
}
// Removes a trailing (back)slash from a path.
//
// Parameters:
// pPath: A directory path
//
// Return value: The path without a trailing (back)slash.
function withoutTrailingSlash(pPath)
{
if ((pPath == null) || (pPath == undefined))
return "";
var retval = pPath;
if (retval.length > 0)
{
var lastIndex = retval.length - 1;
var lastChar = retval.charAt(lastIndex);
if ((lastChar == "\\") || (lastChar == "/"))
retval = retval.substr(0, lastIndex);
}
return retval;
}
// Adds double-quotes around a string if the string contains spaces.
//
// Parameters:
// pStr: A string to add double-quotes around if it has spaces
//
// Return value: The string with double-quotes if it contains spaces. If the
// string doesn't contain spaces, then the same string will be
// returned.
function quoteStrWithSpaces(pStr)
{
if (typeof(pStr) != "string")
return "";
var strCopy = pStr;
if (pStr.indexOf(" ") > -1)
strCopy = "\"" + pStr + "\"";
return strCopy;
}
// Given a message header field list type number (i.e., the 'type' property for an
// entry in the field_list array in a message header), this returns a text label
// to be used for outputting the field.
//
// Parameters:
// pFieldListType: A field_list entry type (numeric)
// pIncludeTrailingColon: Optional boolean - Whether or not to include a trailing ":"
// at the end of the returned string. Defaults to true.
//
// Return value: A text label for the field (a string)
function msgHdrFieldListTypeToLabel(pFieldListType, pIncludeTrailingColon)
{
// The page at this URL lists the header field types:
// http://synchro.net/docs/smb.html#Header Field Types:

nightfox
committed
var fieldTypeLabel = "Unknown (" + pFieldListType.toString() + ")";
16137
16138
16139
16140
16141
16142
16143
16144
16145
16146
16147
16148
16149
16150
16151
16152
16153
16154
16155
16156
16157
16158
16159
16160
16161
16162
16163
16164
16165
16166
16167
16168
16169
16170
16171
16172
16173
16174
16175
16176
16177
16178
16179
16180
16181
16182
16183
16184
16185
16186
16187
16188
16189
16190
16191
16192
16193
16194
16195
switch (pFieldListType)
{
case 0: // Sender
fieldTypeLabel = "Sender";
break;
case 1: // Sender Agent
fieldTypeLabel = "Sender Agent";
break;
case 2: // Sender net type
fieldTypeLabel = "Sender Net Type";
break;
case 3: // Sender Net Address
fieldTypeLabel = "Sender Net Address";
break;
case 4: // Sender Agent Extension
fieldTypeLabel = "Sender Agent Extension";
break;
case 5: // Sending agent (Sender POS)
fieldTypeLabel = "Sender Agent";
break;
case 6: // Sender organization
fieldTypeLabel = "Sender Organization";
break;
case 16: // Author
fieldTypeLabel = "Author";
break;
case 17: // Author Agent
fieldTypeLabel = "Author Agent";
break;
case 18: // Author Net Type
fieldTypeLabel = "Author Net Type";
break;
case 19: // Author Net Address
fieldTypeLabel = "Author Net Address";
break;
case 20: // Author Extension
fieldTypeLabel = "Author Extension";
break;
case 21: // Author Agent (Author POS)
fieldTypeLabel = "Author Agent";
break;
case 22: // Author Organization
fieldTypeLabel = "Author Organization";
break;
case 32: // Reply To
fieldTypeLabel = "Reply To";
break;
case 33: // Reply To agent
fieldTypeLabel = "Reply To Agent";
break;
case 34: // Reply To net type
fieldTypeLabel = "Reply To net type";
break;
case 35: // Reply To net address
fieldTypeLabel = "Reply To net address";
break;
case 36: // Reply To extension
fieldTypeLabel = "Reply To (extended)";
break;

nightfox
committed
case 37: // Reply To position
16197
16198
16199
16200
16201
16202
16203
16204
16205
16206
16207
16208
16209
16210
16211
16212
16213
fieldTypeLabel = "Reply To position";
break;
case 38: // Reply To organization (0x26 hex)
fieldTypeLabel = "Reply To organization";
break;
case 48: // Recipient (0x30 hex)
fieldTypeLabel = "Recipient";
break;
case 162: // Seen-by
fieldTypeLabel = "Seen-by";
break;
case 163: // Path
fieldTypeLabel = "Path";
break;
case 176: // RFCC822 Header
fieldTypeLabel = "RFCC822 Header";
break;

nightfox
committed
case 177: // RFC822 MSGID
fieldTypeLabel = "RFC822 MSGID";
break;
case 178: // RFC822 REPLYID
fieldTypeLabel = "RFC822 REPLYID";
break;
case 240: // UNKNOWN
fieldTypeLabel = "UNKNOWN";
break;
case 241: // UNKNOWNASCII
fieldTypeLabel = "UNKNOWN (ASCII)";
break;
case 255:
fieldTypeLabel = "UNUSED";
break;

nightfox
committed
fieldTypeLabel = "Unknown (" + pFieldListType.toString() + ")";
break;
}
var includeTrailingColon = (typeof(pIncludeTrailingColon) == "boolean" ? pIncludeTrailingColon : true);
if (includeTrailingColon)
fieldTypeLabel += ":";
return fieldTypeLabel;
}

nightfox
committed
16241
16242
16243
16244
16245
16246
16247
16248
16249
16250
16251
16252
16253
16254
16255
16256
16257
// Capitalizes the first character of a string.
//
// Parameters:
// pStr: The string to capitalize
//
// Return value: A version of the sting with the first character capitalized
function capitalizeFirstChar(pStr)
{
var retStr = "";
if (typeof(pStr) == "string")
{
if (pStr.length > 0)
retStr = pStr.charAt(0).toUpperCase() + pStr.slice(1);
}
return retStr;
}
16258
16259
16260
16261
16262
16263
16264
16265
16266
16267
16268
16269
16270
16271
16272
16273
16274
16275
16276
16277
16278
16279
16280
16281
16282
16283
16284
16285
16286
16287
16288
16289
16290
16291
16292
16293
16294
16295
16296
16297
16298
16299
16300
16301
16302
16303
16304
16305
16306
16307
16308
16309
16310
16311
16312
16313
16314
16315
16316
16317
16318
16319
16320
16321
16322
16323
16324
16325
16326
16327
16328
16329
16330
16331
16332
16333
16334
16335
16336
16337
16338
16339
16340
16341
16342
16343
16344
16345
16346
16347
16348
16349
16350
16351
16352
16353
16354
16355
16356
16357
16358
// Parses a list of numbers (separated by commas or spaces), which may contain
// ranges separated by dashes. Returns an array of the individual numbers.
//
// Parameters:
// pList: A comma-separated list of numbers, some which may contain
// 2 numbers separated by a dash denoting a range of numbers.
//
// Return value: An array of the individual numbers from the list
function parseNumberList(pList)
{
if (typeof(pList) != "string")
return [];
var numberList = [];
// Split pList on commas or spaces
var commaOrSpaceSepArray = pList.split(/[\s,]+/);
if (commaOrSpaceSepArray.length > 0)
{
// Go through the comma-separated array - If the element is a
// single number, then append it to the number list to be returned.
// If there is a range (2 numbers separated by a dash), then
// append each number in the range individually to the array to be
// returned.
for (var i = 0; i < commaOrSpaceSepArray.length; ++i)
{
// If it's a single number, append it to numberList.
if (/^[0-9]+$/.test(commaOrSpaceSepArray[i]))
numberList.push(+commaOrSpaceSepArray[i]);
// If there are 2 numbers separated by a dash, then split it on the
// dash and generate the intermediate numbers.
else if (/^[0-9]+-[0-9]+$/.test(commaOrSpaceSepArray[i]))
{
var twoNumbers = commaOrSpaceSepArray[i].split("-");
if (twoNumbers.length == 2)
{
var num1 = +twoNumbers[0];
var num2 = +twoNumbers[1];
// If the 1st number is bigger than the 2nd, then swap them.
if (num1 > num2)
{
var temp = num1;
num1 = num2;
num2 = temp;
}
// Append each individual number in the range to numberList.
for (var number = num1; number <= num2; ++number)
numberList.push(number);
}
}
}
}
return numberList;
}
// Inputs a single keypress from the user from a list of valid keys, allowing
// input modes (see K_* in sbbsdefs.js for mode bits). This is similar to
// console.getkeys(), except that this allows mode bits (such as K_NOCRLF, etc.).
//
// Parameters:
// pAllowedKeys: A list of allowed keys (string)
// pMode: Mode bits (see K_* in sbbsdefs.js)
//
// Return value: The user's inputted keypress
function getAllowedKeyWithMode(pAllowedKeys, pMode)
{
var userInput = "";
var keypress = "";
var i = 0;
var matchedKeypress = false;
while (!matchedKeypress)
{
keypress = console.getkey(K_NOECHO|pMode);
// Check to see if the keypress is one of the allowed keys
for (i = 0; i < pAllowedKeys.length; ++i)
{
if (keypress == pAllowedKeys[i])
userInput = keypress;
else if (keypress.toUpperCase() == pAllowedKeys[i])
userInput = keypress.toUpperCase();
else if (keypress.toLowerCase() == pAllowedKeys[i])
userInput = keypress.toLowerCase();
if (userInput.length > 0)
{
matchedKeypress = true;
// If K_NOECHO is not in pMode, then output the user's keypress
if ((pMode & K_NOECHO) == 0)
console.print(userInput);
// If K_NOCRLF is not in pMode, then output a CRLF
if ((pMode & K_NOCRLF) == 0)
console.crlf();
break;
}
}
}
return userInput;
}
16359
16360
16361
16362
16363
16364
16365
16366
16367
16368
16369
16370
16371
16372
16373
16374
16375
16376
16377
16378
16379
16380
16381
16382
16383
16384
16385
16386
16387
16388
16389
16390
16391
16392
16393
// Loads a text file (an .ans or .asc) into an array. This will first look for
// an .ans version, and if exists, convert to Synchronet colors before loading
// it. If an .ans doesn't exist, this will look for an .asc version.
//
// Parameters:
// pFilenameBase: The filename without the extension
// pMaxNumLines: Optional - The maximum number of lines to load from the text file
//
// Return value: An array containing the lines from the text file
function loadTextFileIntoArray(pFilenameBase, pMaxNumLines)
{
if (typeof(pFilenameBase) != "string")
return new Array();
var maxNumLines = (typeof(pMaxNumLines) == "number" ? pMaxNumLines : -1);
var txtFileLines = new Array();
// See if there is a header file that is made for the user's terminal
// width (areaChgHeader-<width>.ans/asc). If not, then just go with
// msgHeader.ans/asc.
var txtFileExists = true;
var txtFilenameFullPath = gStartupPath + pFilenameBase;
var txtFileFilename = "";
if (file_exists(txtFilenameFullPath + "-" + console.screen_columns + ".ans"))
txtFileFilename = txtFilenameFullPath + "-" + console.screen_columns + ".ans";
else if (file_exists(txtFilenameFullPath + "-" + console.screen_columns + ".asc"))
txtFileFilename = txtFilenameFullPath + "-" + console.screen_columns + ".asc";
else if (file_exists(txtFilenameFullPath + ".ans"))
txtFileFilename = txtFilenameFullPath + ".ans";
else if (file_exists(txtFilenameFullPath + ".asc"))
txtFileFilename = txtFilenameFullPath + ".asc";
else
txtFileExists = false;
if (txtFileExists)
{
var syncConvertedHdrFilename = txtFileFilename;
// If the user's console doesn't support ANSI and the header file is ANSI,
// then convert it to Synchronet attribute codes and read that file instead.
if (!console.term_supports(USER_ANSI) && (getStrAfterPeriod(txtFileFilename).toUpperCase() == "ANS"))
{
syncConvertedHdrFilename = txtFilenameFullPath + "_converted.asc";
if (!file_exists(syncConvertedHdrFilename))
{
if (getStrAfterPeriod(txtFileFilename).toUpperCase() == "ANS")
{
var filenameBase = txtFileFilename.substr(0, dotIdx);
var cmdLine = system.exec_dir + "ans2asc \"" + txtFileFilename + "\" \""
+ syncConvertedHdrFilename + "\"";
// Note: Both system.exec(cmdLine) and
// bbs.exec(cmdLine, EX_NATIVE, gStartupPath) could be used to
// execute the command, but system.exec() seems noticeably faster.
system.exec(cmdLine);
}
else
syncConvertedHdrFilename = txtFileFilename;
}
}
16416
16417
16418
16419
16420
16421
16422
16423
16424
16425
16426
16427
16428
16429
16430
16431
16432
16433
16434
16435
16436
/*
// If the header file is ANSI, then convert it to Synchronet attribute
// codes and read that file instead. This is done so that this script can
// accurately get the file line lengths using console.strlen().
var syncConvertedHdrFilename = txtFilenameFullPath + "_converted.asc";
if (!file_exists(syncConvertedHdrFilename))
{
if (getStrAfterPeriod(txtFileFilename).toUpperCase() == "ANS")
{
var filenameBase = txtFileFilename.substr(0, dotIdx);
var cmdLine = system.exec_dir + "ans2asc \"" + txtFileFilename + "\" \""
+ syncConvertedHdrFilename + "\"";
// Note: Both system.exec(cmdLine) and
// bbs.exec(cmdLine, EX_NATIVE, gStartupPath) could be used to
// execute the command, but system.exec() seems noticeably faster.
system.exec(cmdLine);
}
else
syncConvertedHdrFilename = txtFileFilename;
}
*/
16437
16438
16439
16440
16441
16442
16443
16444
16445
16446
16447
16448
16449
16450
16451
16452
16453
16454
16455
16456
16457
16458
16459
16460
16461
16462
16463
16464
16465
16466
// Read the header file into txtFileLines
var hdrFile = new File(syncConvertedHdrFilename);
if (hdrFile.open("r"))
{
var fileLine = null;
while (!hdrFile.eof)
{
// Read the next line from the header file.
fileLine = hdrFile.readln(2048);
// fileLine should be a string, but I've seen some cases
// where it isn't, so check its type.
if (typeof(fileLine) != "string")
continue;
// Make sure the line isn't longer than the user's terminal
//if (fileLine.length > console.screen_columns)
// fileLine = fileLine.substr(0, console.screen_columns);
txtFileLines.push(fileLine);
// If the header array now has the maximum number of lines, then
// stop reading the header file.
if (txtFileLines.length == maxNumLines)
break;
}
hdrFile.close();
}
}
return txtFileLines;
}
// Returns the portion (if any) of a string after the period.
//
// Parameters:
// pStr: The string to extract from
//
// Return value: The portion of the string after the dot, if there is one. If
// not, then an empty string will be returned.
function getStrAfterPeriod(pStr)
{
var strAfterPeriod = "";
var dotIdx = pStr.lastIndexOf(".");
if (dotIdx > -1)
strAfterPeriod = pStr.substr(dotIdx+1);
return strAfterPeriod;
}
/////////////////////////////////////////////////////////////////////////
// Debug helper & error output function
16485
16486
16487
16488
16489
16490
16491
16492
16493
16494
16495
16496
16497
16498
16499
16500
16501
16502
16503
16504
16505
16506
16507
16508
16509
16510
16511
16512
// Writes some text on the screen at a given location with a given pause.
//
// Parameters:
// pX: The column number on the screen at which to write the message
// pY: The row number on the screen at which to write the message
// pText: The text to write
// pPauseMS: The pause time, in milliseconds
// pClearLineAttrib: Optional - The color/attribute to clear the line with.
// If not specified or null is specified, defaults to normal attribute.
// pClearLineAfter: Whether or not to clear the line again after the message is dispayed and
// the pause occurred. This is optional.
function writeWithPause(pX, pY, pText, pPauseMS, pClearLineAttrib, pClearLineAfter)
{
var clearLineAttrib = "\1n";
if ((pClearLineAttrib != null) && (typeof(pClearLineAttrib) == "string"))
clearLineAttrib = pClearLineAttrib;
console.gotoxy(pX, pY);
console.cleartoeol(clearLineAttrib);
console.print(pText);
if (pPauseMS > 0)
mswait(pPauseMS);
if (pClearLineAfter)
{
console.gotoxy(pX, pY);
console.cleartoeol(clearLineAttrib);
}
}