This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
deb-mbse/mbsebbs/dispfile.c

683 lines
14 KiB
C
Raw Normal View History

/*****************************************************************************
*
* $Id$
* Purpose ...............: Display ANSI/ASCII textfiles
*
*****************************************************************************
* Copyright (C) 1997-2005
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* MBSE BBS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MBSE BBS; see the file COPYING. If not, write to the Free
2003-08-15 20:05:34 +00:00
* Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*****************************************************************************/
2002-06-30 12:48:44 +00:00
#include "../config.h"
2004-02-21 17:22:00 +00:00
#include "../lib/mbselib.h"
#include "../lib/mbse.h"
2002-01-07 19:16:03 +00:00
#include "../lib/users.h"
#include "../lib/msgtext.h"
#include "../lib/msg.h"
#include "funcs.h"
#include "language.h"
#include "oneline.h"
#include "misc.h"
#include "timeout.h"
#include "timecheck.h"
#include "exitinfo.h"
#include "mail.h"
#include "email.h"
2003-02-07 20:49:01 +00:00
#include "input.h"
#include "dispfile.h"
2003-04-12 11:12:26 +00:00
#include "filesub.h"
#include "term.h"
2004-11-03 20:48:45 +00:00
#include "ttyio.h"
2005-10-07 20:42:35 +00:00
extern int rows;
/*
* Function returns total number of bbs users
*/
int TotalUsers(void);
int TotalUsers(void)
{
2004-11-03 20:48:45 +00:00
FILE *pUsrConfig;
int ch = 0;
char *temp;
struct userhdr uhdr;
struct userrec u;
temp = calloc(PATH_MAX, sizeof(char));
2005-08-29 12:50:02 +00:00
snprintf(temp, PATH_MAX, "%s/etc/users.data", getenv("MBSE_ROOT"));
2004-11-03 20:48:45 +00:00
if(( pUsrConfig = fopen(temp,"rb")) == NULL)
WriteError("ControlCodeK: Can't open users file %s for reading", temp);
else {
fread(&uhdr, sizeof(uhdr), 1, pUsrConfig);
while (fread(&u, uhdr.recsize, 1, pUsrConfig) == 1)
if ((!u.Deleted) && (strlen(u.sUserName) > 0))
ch++;
fclose(pUsrConfig);
}
free(temp);
return ch;
}
2003-02-07 20:49:01 +00:00
/*
* Function will display a aras rulefile to the user.
* Searches in rules directory first for a file with
* the full name of the area, then the fule name of the
* area with a .rul suffix, and finally for the first
* 8 characters of the areaname with a .rul suffix.
* The search is case insensitive.
*
* Menu 221.
*/
void DisplayRules(void)
{
DIR *dp;
struct dirent *de;
int Found = FALSE;
2005-08-29 12:50:02 +00:00
char temp[PATH_MAX];
2003-02-07 20:49:01 +00:00
if ((dp = opendir(CFG.rulesdir)) == NULL) {
WriteError("$Can't open directory %s", CFG.rulesdir);
2004-11-03 20:48:45 +00:00
Enter(1);
2003-02-07 20:49:01 +00:00
/* Can't open directory for listing: */
2004-11-03 20:48:45 +00:00
pout(LIGHTRED, BLACK, (char *) Language(290));
Enter(2);
2003-02-07 20:49:01 +00:00
Pause();
return;
}
while ((de = readdir(dp))) {
if (de->d_name[0] != '.') {
strcpy(temp, msgs.Tag);
if (strcasecmp(de->d_name, temp) == 0) {
Found = TRUE;
2005-08-29 12:50:02 +00:00
snprintf(temp, PATH_MAX, "%s/%s", CFG.rulesdir, de->d_name);
2003-02-07 20:49:01 +00:00
break;
}
2005-08-29 12:50:02 +00:00
snprintf(temp, PATH_MAX, "%s.rul", temp);
2003-02-07 20:49:01 +00:00
if (strcasecmp(de->d_name, temp) == 0) {
Found = TRUE;
2005-08-29 12:50:02 +00:00
snprintf(temp, PATH_MAX, "%s/%s", CFG.rulesdir, de->d_name);
2003-02-07 20:49:01 +00:00
break;
}
memset(&temp, 0, sizeof(temp));
strncpy(temp, msgs.Tag, 8);
2005-08-29 12:50:02 +00:00
snprintf(temp, PATH_MAX, "%s.rul", temp);
2003-02-07 20:49:01 +00:00
if (strcasecmp(de->d_name, temp) == 0) {
Found = TRUE;
2005-08-29 12:50:02 +00:00
snprintf(temp, PATH_MAX, "%s/%s", CFG.rulesdir, de->d_name);
2003-02-07 20:49:01 +00:00
break;
}
}
}
closedir(dp);
if (Found) {
Syslog('+', "Display rules: %s", temp);
DisplayTextFile(temp);
} else {
Syslog('+', "Display rules for %s failed, not found", msgs.Tag);
Enter(1);
/* No rules found for this area */
2004-11-03 20:48:45 +00:00
pout(LIGHTRED, BLACK, (char *) Language(13));
Enter(2);
2003-02-07 20:49:01 +00:00
Pause();
}
}
/*
* Function will display a flat ascii textfile to the
* user without control codes. This is used to display
* area rules, but is also called from the menu function
* that will display a textfile or the contents of a archive.
*/
int DisplayTextFile(char *filename)
{
2004-11-03 20:48:45 +00:00
FILE *fp;
char *buf;
int i, x, z, lc = 0;
unsigned char c;
2003-02-07 20:49:01 +00:00
if ((fp = fopen(filename, "r")) == NULL) {
WriteError("$DisplayTextFile(%s) failed");
return FALSE;
}
buf = calloc(81, sizeof(char));
clear();
colour(CFG.TextColourF, CFG.TextColourB);
while (fgets(buf, 79, fp)) {
i = strlen(buf);
for (x = 0; x < i; x++) {
2004-11-03 20:48:45 +00:00
c = (*(buf + x) & 0xff);
2003-02-07 20:49:01 +00:00
if (isprint(c))
2004-11-03 20:48:45 +00:00
PUTCHAR(c);
2003-02-07 20:49:01 +00:00
}
2004-11-03 20:48:45 +00:00
Enter(1);
2003-02-07 20:49:01 +00:00
lc++;
2005-10-07 20:42:35 +00:00
if ((lc >= rows) && (lc < 1000)) {
2003-02-07 20:49:01 +00:00
lc = 0;
2003-04-12 11:12:26 +00:00
/* More (Y/n/=) */
pout(CFG.MoreF, CFG.MoreB, (char *) Language(61));
alarm_on();
2004-11-03 20:48:45 +00:00
z = toupper(Readkey());
2003-04-12 11:12:26 +00:00
if (z == Keystroke(61, 1)) {
2004-11-03 20:48:45 +00:00
Enter(1);
2003-04-12 11:12:26 +00:00
fclose(fp);
free(buf);
return TRUE;
}
if (z == Keystroke(61, 2))
lc = 50000;
Blanker(strlen(Language(61)));
2003-02-07 20:49:01 +00:00
colour(CFG.TextColourF, CFG.TextColourB);
}
}
fclose(fp);
free(buf);
Enter(1);
/* Press ENTER to continue */
2003-04-12 11:12:26 +00:00
language(CFG.MoreF, CFG.MoreB, 436);
2003-02-07 20:49:01 +00:00
alarm_on();
2004-11-03 20:48:45 +00:00
Readkey();
2003-02-07 20:49:01 +00:00
return TRUE;
}
/*
* Function will display textfile in either ansi or ascii and
* display control codes if they exist.
* Returns Success if it can display the requested file
*/
int DisplayFile(char *filename)
{
2004-11-03 20:48:45 +00:00
FILE *pFileName;
long iSec = 0;
char *sFileName, *tmp, *tmp1, newfile[PATH_MAX];
int i, x;
unsigned char c;
2003-04-12 11:12:26 +00:00
sFileName = calloc(16385, sizeof(char));
tmp = calloc(PATH_MAX, sizeof(char));
tmp1 = calloc(PATH_MAX, sizeof(char));
/*
* Open the file in the following search order:
* 1 - if GraphMode -> users language .ans
* 2 - if GraphMode -> default language .ans
* 3 - users language .asc
* 4 - default language .asc
* 5 - Abort, there is no file to show.
*/
pFileName = NULL;
if (exitinfo.GraphMode) {
2005-08-29 12:50:02 +00:00
snprintf(newfile, PATH_MAX, "%s/%s.ans", lang.TextPath, filename);
2003-04-12 11:12:26 +00:00
if ((pFileName = fopen(newfile, "rb")) == NULL) {
2005-08-29 12:50:02 +00:00
snprintf(newfile, PATH_MAX, "%s/%s.ans", CFG.bbs_txtfiles, filename);
2003-04-12 11:12:26 +00:00
pFileName = fopen(newfile, "rb");
}
2003-04-12 11:12:26 +00:00
}
if (pFileName == NULL) {
2005-08-29 12:50:02 +00:00
snprintf(newfile, PATH_MAX, "%s/%s.asc", lang.TextPath, filename);
2003-04-12 11:12:26 +00:00
if ((pFileName = fopen(newfile, "rb")) == NULL) {
2005-08-29 12:50:02 +00:00
snprintf(newfile, PATH_MAX, "%s/%s.asc", CFG.bbs_txtfiles, filename);
2003-04-12 11:12:26 +00:00
if ((pFileName = fopen(newfile, "rb")) == NULL) {
free(sFileName);
free(tmp);
free(tmp1);
return FALSE;
}
}
2003-04-12 11:12:26 +00:00
}
Syslog('B', "Displayfile %s", newfile);
2003-04-12 11:12:26 +00:00
while (!feof(pFileName)) {
i = fread(sFileName, sizeof(char), 16384, pFileName);
for (x = 0; x < i; x++) {
2004-11-03 20:48:45 +00:00
c = *(sFileName + x) & 0xff;
switch (c) {
2003-04-12 11:12:26 +00:00
case '': ControlCodeU(sFileName[++x]);
break;
case '': ControlCodeF(sFileName[++x]);
break;
case ' ': ControlCodeK(sFileName[++x]);
break;
2004-11-03 20:48:45 +00:00
case '': alarm_on();
Readkey();
2003-04-12 11:12:26 +00:00
break;
case '': /*
* This code will allow you to specify a security level
* in front of the text, ie ^B32000^Bthis is a test^B
* will print this is a test only if you have security
* above 32000. Only one set of control chars per line.
* You cannot have multiple securitys etc
*/
x++;
strcpy(tmp1, "");
while (*(sFileName + x) != '') {
2005-08-29 12:50:02 +00:00
snprintf(tmp, PATH_MAX, "%c", *(sFileName + x));
2003-04-12 11:12:26 +00:00
strcat(tmp1, tmp);
x++;
}
x++;
iSec = atoi(tmp1);
while ((x <= i) && (*(sFileName + x) != '')) {
if (exitinfo.Security.level >= iSec)
2004-11-03 20:48:45 +00:00
PUTCHAR(*(sFileName + x));
2003-04-12 11:12:26 +00:00
x++;
}
break;
2004-11-03 20:48:45 +00:00
case '': sleep(1);
2003-04-12 11:12:26 +00:00
break;
2004-11-03 20:48:45 +00:00
case '\n': Enter(1); /* Insert <cr>, we are in raw mode */
break;
case '\r': break; /* If the file has <cr> chars (DOS), eat them */
default: PUTCHAR(*(sFileName + x));
2003-04-12 11:12:26 +00:00
} /* switch */
} /* for */
} /* while !eof */
fclose(pFileName);
free(sFileName);
free(tmp);
free(tmp1);
return TRUE;
}
int DisplayFileEnter(char *File)
{
2003-04-12 11:12:26 +00:00
int rc;
2003-04-12 11:12:26 +00:00
rc = DisplayFile(File);
Enter(1);
/* Press ENTER to continue */
2005-08-20 12:27:08 +00:00
language(LIGHTMAGENTA, BLACK, 436);
2003-04-12 11:12:26 +00:00
alarm_on();
2004-11-03 20:48:45 +00:00
Readkey();
2003-04-12 11:12:26 +00:00
return rc;
}
void ControlCodeF(int ch)
{
2004-11-03 20:48:45 +00:00
char temp[81];
/* Update user info */
ReadExitinfo();
2004-11-03 20:48:45 +00:00
switch (toupper(ch)) {
case '!':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.sProtocol);
break;
case 'A':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%ld", exitinfo.Uploads);
break;
case 'B':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%ld", exitinfo.Downloads);
break;
case 'C':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%lu", exitinfo.DownloadK);
break;
case 'D':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%lu", exitinfo.UploadK);
break;
case 'E':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%lu", exitinfo.DownloadK + exitinfo.UploadK);
break;
case 'F':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%lu", LIMIT.DownK);
break;
case 'H':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%d", iAreaNumber);
break;
case 'I':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", sAreaDesc);
break;
case 'J':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%u", LIMIT.DownF);
break;
case 'K':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", LIMIT.Description);
break;
default:
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, " ");
2004-11-03 20:48:45 +00:00
}
PUTSTR(temp);
}
void ControlCodeU(int ch)
{
2004-11-03 20:48:45 +00:00
char temp[81];
/*
* Update user info
*/
TimeCheck();
ReadExitinfo();
2004-11-03 20:48:45 +00:00
switch (toupper(ch)) {
case 'A':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.sUserName);
break;
case 'B':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.sLocation);
break;
case 'C':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.sVoicePhone);
break;
case 'D':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.sDataPhone);
break;
case 'E':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", LastLoginDate);
break;
case 'F':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s %s", StrDateDMY(exitinfo.tFirstLoginDate), StrTimeHMS(exitinfo.tFirstLoginDate));
break;
case 'G':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", LastLoginTime);
break;
case 'H':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%d", exitinfo.Security.level);
break;
case 'I':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%d", exitinfo.iTotalCalls);
break;
case 'J':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%d", exitinfo.iTimeUsed);
break;
case 'K':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%d", exitinfo.iConnectTime);
break;
case 'L':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%d", exitinfo.iTimeLeft);
break;
case 'M':
2005-10-07 20:42:35 +00:00
snprintf(temp, 81, "%d", rows);
break;
case 'N':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", FirstName);
break;
case 'O':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", LastName);
break;
case 'Q':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.ieNEWS ? (char *) Language(147) : (char *) Language(148));
break;
case 'P':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.GraphMode ? (char *) Language(147) : (char *) Language(148));
break;
case 'R':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.HotKeys ? (char *) Language(147) : (char *) Language(148));
break;
case 'S':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%d", exitinfo.iTimeUsed + exitinfo.iTimeLeft);
break;
case 'T':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.sDateOfBirth);
break;
case 'U':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%d", exitinfo.iPosted);
break;
case 'X':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", lang.Name);
break;
case 'Y':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.sHandle);
break;
case 'Z':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.DoNotDisturb ? (char *) Language(147) : (char *) Language(148));
break;
case '1':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.MailScan ? (char *) Language(147) : (char *) Language(148));
break;
case '2':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.ieFILE ? (char *) Language(147) : (char *) Language(148));
break;
case '3':
switch(exitinfo.MsgEditor) {
2005-08-29 12:50:02 +00:00
case LINEEDIT: snprintf(temp, 81, "%s", Language(387));
break;
2005-08-29 12:50:02 +00:00
case FSEDIT: snprintf(temp, 81, "%s", Language(388));
break;
2005-08-29 12:50:02 +00:00
case EXTEDIT: snprintf(temp, 81, "%s", Language(389));
break;
2005-08-29 12:50:02 +00:00
default: snprintf(temp, 81, "?");
}
break;
case '4':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.FSemacs ? (char *) Language(147) : (char *) Language(148));
break;
case '5':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.address[0]);
break;
case '6':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.address[1]);
break;
case '7':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.address[2]);
break;
2003-03-02 13:29:33 +00:00
case '8':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", exitinfo.OL_ExtInfo ? (char *) Language(147) : (char *) Language(148));
2003-03-02 13:29:33 +00:00
break;
2004-02-24 22:09:27 +00:00
case '9':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", getftnchrs(exitinfo.Charset));
2004-02-24 22:09:27 +00:00
break;
default:
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, " ");
2004-11-03 20:48:45 +00:00
}
PUTSTR(temp);
}
void ControlCodeK(int ch)
{
2004-11-03 20:48:45 +00:00
FILE *pCallerLog;
char sDataFile[PATH_MAX], temp[81];
lastread LR;
2004-11-03 20:48:45 +00:00
switch (toupper(ch)) {
case 'A':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", (char *) GetDateDMY());
break;
case 'B':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", (char *) GetLocalHMS());
break;
case 'C':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", (char *) GLCdate());
break;
case 'D':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", (char *) GLCdateyy());
break;
case 'E':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%ld", Speed());
break;
case 'F':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", LastCaller);
break;
case 'G':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%d", TotalUsers());
break;
case 'H':
2005-08-29 12:50:02 +00:00
snprintf(sDataFile, PATH_MAX, "%s/etc/sysinfo.data", getenv("MBSE_ROOT"));
if((pCallerLog = fopen(sDataFile, "rb")) != NULL) {
2004-11-03 20:48:45 +00:00
fread(&SYSINFO, sizeof(SYSINFO), 1, pCallerLog);
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%ld", SYSINFO.SystemCalls);
2004-11-03 20:48:45 +00:00
fclose(pCallerLog);
}
break;
case 'I':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%d", iMsgAreaNumber + 1);
break;
case 'J':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", sMsgAreaDesc);
break;
case 'K':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", Oneliner_Get());
break;
case 'L':
SetMsgArea(iMsgAreaNumber);
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%ld", MsgBase.Total);
break;
case 'M':
LR.UserID = grecno;
if (Msg_Open(sMsgAreaBase)) {
2004-11-03 20:48:45 +00:00
if (Msg_GetLastRead(&LR) == TRUE) {
if (LR.HighReadMsg > MsgBase.Highest)
LR.HighReadMsg = MsgBase.Highest;
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%ld", LR.HighReadMsg);
2004-11-03 20:48:45 +00:00
} else
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "?");
2004-11-03 20:48:45 +00:00
Msg_Close();
}
break;
case 'N':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s", sMailbox);
break;
case 'O':
SetEmailArea(sMailbox);
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%ld", EmailBase.Total);
break;
case 'P':
2005-10-08 21:05:28 +00:00
SetEmailArea(sMailbox);
LR.UserID = grecno;
2005-10-08 21:05:28 +00:00
if (Msg_Open(sMailpath)) {
2004-11-03 20:48:45 +00:00
if (Msg_GetLastRead(&LR) == TRUE) {
if (LR.HighReadMsg > EmailBase.Highest)
LR.HighReadMsg = EmailBase.Highest;
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%ld", LR.HighReadMsg);
2004-11-03 20:48:45 +00:00
} else
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "?");
2004-11-03 20:48:45 +00:00
Msg_Close();
}
break;
2001-11-12 21:42:17 +00:00
case 'Q':
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, "%s %s", StrDateDMY(LastCallerTime), StrTimeHMS(LastCallerTime));
2001-11-12 21:42:17 +00:00
break;
default:
2005-08-29 12:50:02 +00:00
snprintf(temp, 81, " ");
2004-11-03 20:48:45 +00:00
}
PUTSTR(temp);
}