/* List.c */
#include "Sys.h"
#include <signal.h>
#include <setjmp.h>
#include "Util.h"
#include "RCmd.h"
#include "Xfer.h"
#include "Cmds.h"
#include "List.h"
#include "Glob.h"
#include "Sio.h"
#include "Bookmark.h"
#include "Complete.h"
jmp_buf gPDirJmp;
jmp_buf gLocalListJmp;
LineList gRedir;
extern int gStdout;
extern longstring gPager;
extern Bookmark gRmtInfo;
extern int gNetworkTimeout;
int
ListReceiveProc(XferSpecPtr xp)
{
int nread;
int nwrote;
int fd;
char xbuf[256];
char buf2[256];
fd = xp->outStream;
for (;;) {
nread = BufferGets(xbuf, sizeof(xbuf), xp);
if (nread <= 0)
break;
if (xp->outIsTTY != 0) {
if (xbuf[nread - 1] == '\n')
xbuf[--nread] = '\0';
MakeStringPrintable(buf2, (unsigned char *) xbuf, sizeof(buf2));
MultiLinePrintF("%s\n", buf2);
AddLine(&gRedir, buf2);
CompleteParse(buf2);
} else {
nwrote = Swrite(xp->outStream, xbuf, nread, gNetworkTimeout);
if (nwrote < 0) {
nread = nwrote;
break;
}
if (xbuf[nread - 1] == '\n')
xbuf[--nread] = '\0';
AddLine(&gRedir, xbuf);
CompleteParse(xbuf);
}
}
return (nread); /* 0 or -1 */
} /* ListReceiveProc */
int
ListToMemoryReceiveProc(XferSpecPtr xp)
{
int nread;
char xbuf[256];
for (;;) {
nread = BufferGets(xbuf, sizeof(xbuf), xp);
if (nread <= 0)
break;
if (xbuf[nread - 1] == '\n')
xbuf[--nread] = '\0';
AddLine((LineListPtr) xp->miscPtr, xbuf);
}
return (nread); /* 0 or -1 */
} /* ListToMemoryReceiveProc */
void
ListToMemory(LineListPtr fileList, char *cmd, char *flags, char *what)
{
XferSpecPtr xp;
fileList->first = fileList->last = NULL;
/* Setup the parameter block for RDataCmd. Note that we purposely
* leave the other fields unset, since we don't use them, and
* being zeroed-out is okay.
*/
xp = InitXferSpec();
xp->netMode = kNetReading;
xp->xProc = ListToMemoryReceiveProc;
xp->outStream = -1; /* Not used... */
xp->miscPtr = fileList;
SETASCII; /* Directory listings should be in ascii mode. */
if ((flags == NULL) || (gRmtInfo.isUnix == 0))
(void) RDataCmd(xp, "%s %s", cmd, what);
else
(void) RDataCmd(xp, "%s %s %s", cmd, flags, what);
DoneWithXferSpec(xp); /* Doesn't dispose miscPtr. */
} /* ListToMemory */
int
FileListReceiveProc(XferSpecPtr xp)
{
int nread;
longstring str, buf;
char *cp;
int c;
for (;;) {
nread = BufferGets(buf, sizeof(buf), xp);
if (nread <= 0)
break;
cp = buf;
/* Unix dependency: ls message */
if (strncmp(buf, "can not access", SZ(14)) == 0) {
EPrintF("%s", buf);
return (0L);
}
cp += nread - 2; /* Want last char of name, but also have \n. */
if (gRmtInfo.isUnix) {
c = *cp;
switch(c) {
/* Unix dependency: ls -F format. */
case '/': c = 'd'; goto subt;
case '@': c = 'l'; goto subt;
case '*': c = '-'; goto subt;
/* No (supported) suffix, so treat it like a plain file. */
default: c = '-'; cp[1] = '\0'; break;
subt: *cp = '\0'; /* Remove suffix. */
}
} else {
/* For non unix, just have to assume file. */
c = '-';
cp[1] = '\0';
}
/* Just want the item names, no path prefixes. */
cp = strrchr(buf, '/');
if (cp != NULL) {
cp = Strncpy(str, cp + 1, sizeof(str));
} else {
cp = Strncpy(str, buf, sizeof(str));
}
/* We write the one-char file type, followed by the item name. */
*buf = c;
(void) Strncpy(buf + 1, str, sizeof(buf) - 1);
AddLine((LineListPtr) xp->miscPtr, buf);
}
return (nread); /* 0 or -1 */
} /* FileListReceiveProc */
void GetFileList(LineListPtr fileList, char *what)
{
XferSpecPtr xp;
fileList->first = fileList->last = NULL;
/* Setup the parameter block for RDataCmd. Note that we purposely
* leave the other fields unset, since we don't use them, and
* being zeroed-out is okay.
*/
xp = InitXferSpec();
xp->netMode = kNetReading;
xp->xProc = FileListReceiveProc;
xp->outStream = -1; /* Not used... */
xp->miscPtr = fileList;
SETASCII; /* Directory listings should be in ascii mode. */
if (gRmtInfo.isUnix)
(void) RDataCmd(xp, "NLST -F %s", what);
else
(void) RDataCmd(xp, "NLST %s", what);
DoneWithXferSpec(xp); /* Doesn't dispose miscPtr. */
} /* GetFileList */
int DoList(int argc, char **argv, char *lsMode)
{
char flags[64];
char flags2[64];
char *cmd;
char thingsToList[256];
int i, wildcards;
XferSpecPtr xp;
SETASCII; /* Directory listings should be in ascii mode. */
thingsToList[0] = '\0';
flags2[0] = '\0';
wildcards = 0;
if (STREQ(lsMode, kListLongMode)) {
cmd = "LIST";
CompleteSetFlags("-l");
flags[0] = '\0';
} else {
cmd = "NLST";
STRNCPY(flags, lsMode + 1);
CompleteSetFlags(lsMode);
}
/* Go through and find all the things that look like dash-flags,
* and combine them into one string. We do the same thing
* for the items to list, so we'll have to groups of things
* to hand to RDataCmd.
*/
for (i=1; i<argc; i++) {
CompleteSetFlags(argv[i]);
if (argv[i][0] == '-')
STRNCAT(flags2, argv[i] + 1);
else {
STRNCAT(thingsToList, " ");
STRNCAT(thingsToList, argv[i]);
if (GLOBCHARSINSTR(argv[i]))
wildcards = 1;
}
}
/* For some unknown reason, traditional servers can do "LIST -t *.tar"
* but not "NLST -t *.tar." This kludges around that limitation.
*/
if ((wildcards) && STREQ(cmd, "NLST")) {
if (flags2[0] == '\0') {
/* They didn't give any other flags, so use NLST, but without
* our usual -CF, but with the wildcard expression.
*/
flags[0] = '\0';
} else {
/* They gave some other flags, but print them a warning, and
* switch them over to LIST, and retain their flags.
*/
cmd = "LIST";
STRNCPY(flags, flags2);
BoldPrintF("Warning: cannot use both flags and wildcards with ls, using dir instead.\n");
}
} else {
/* Append their flags to the default flags. */
STRNCAT(flags, flags2);
}
/* Setup the parameter block for RDataCmd. Note that we purposely
* leave the other fields unset, since we don't use them, and
* being zeroed-out is okay.
*/
xp = InitXferSpec();
xp->netMode = kNetReading;
xp->xProc = ListReceiveProc;
/* xp->inStream = gDataSocket; RDataCmd fills this in when it gets it. */
xp->outStream = gStdout;
/* The rest of the xp parameters can be left zeroed, since we won't
* be using them, and progress reports will not be activated, so
* they won't use them either.
*/
MultiLineInit();
/* Dispose previous buffer, and also be set up for a new one. */
DisposeLineListContents(&gRedir);
if ((flags[0]) && (gRmtInfo.isUnix != 0))
(void) RDataCmd(xp, "%s -%s%s", cmd, flags, thingsToList);
else
(void) RDataCmd(xp, "%s%s", cmd, thingsToList);
DoneWithXferSpec(xp);
return 0;
} /* DoList */
static
void PDirHandler(void)
{
alarm(0);
longjmp(gPDirJmp, 1);
} /* PDirHandler */
/* Do a remote directory listing, to the screen (or file), or
* through your pager.
*/
int ListCmd(int argc, char **argv)
{
char *cp;
char *volatile lsMode;
volatile int result;
volatile int pageMode;
FILE *volatile pager;
volatile int saved;
volatile Sig_t si, sp;
result = kNoErr;
cp = argv[0];
pageMode = kNoPaging;
pager = NULL;
saved = -1;
lsMode = kListShortMode;
if (*cp == 'p') {
/* If the command started with 'p' we should be paging this. */
if (gPager[0] == '\0') {
EPrintF("You haven't specified a program to use as a pager.\n");
EPrintF("You can set this from the preferences screen (prefs command).\n");
return (-1);
}
++cp;
pageMode = kPageMode;
pager = POpen(gPager, "w", 1);
if (pager == NULL) {
RestoreScreen(1);
Error(kDoPerror, "Could not open: %s\n", gPager);
return (-1);
}
/* Now replace our own stdout stream with the pager stream,
* so that writes go to the pager instead.
*/
saved = (volatile int) gStdout;
gStdout = fileno((FILE *) pager);
}
if (*cp == 'd')
lsMode = kListLongMode; /* i.e. "dir" or "pdir" */
CompleteStart(".");
if (setjmp(gPDirJmp) == 0) {
sp = SIGNAL(SIGPIPE, PDirHandler);
si = SIGNAL(SIGINT, PDirHandler);
result = DoList(argc, argv, lsMode);
}
CompleteFinish();
if (pageMode == kPageMode) {
/* Cleanup the mess we made. */
(void) SIGNAL(SIGPIPE, SIG_IGN);
(void) SIGNAL(SIGINT, SIG_IGN);
if (pager != NULL)
PClose((FILE *) pager);
gStdout = saved;
RestoreScreen(1);
}
(void) SIGNAL(SIGPIPE, sp);
(void) SIGNAL(SIGINT, si);
return (result);
} /* ListCmd */
static void SigLocalList(void)
{
alarm(0);
longjmp(gLocalListJmp, 1);
} /* SigLocalList */
/* Run ls on the local host. This is mostly useful for visual mode, where
* it is troublesome to spawn commands.
*/
int LocalListCmd(int argc, char **argv)
{
volatile FILE *fp;
VSig_t si, sp;
longstring str;
int i, cf;
si = (VSig_t) kNoSignalHandler;
sp = (VSig_t) kNoSignalHandler;
str[0] = '\0';
STRNCPY(str, LS);
cf = 1;
if (argc > 1) {
/* Look for "-l", and turn of -CF if we find it. */
for (i=1; (i < argc) && (argv[i][0] == '-'); i++) {
if (strchr(argv[i], 'l') != NULL) {
cf = 0;
break;
}
}
}
if (cf)
STRNCAT(str, " -CF");
for (i=1; i<argc; i++) {
STRNCAT(str, " ");
STRNCAT(str, argv[i]);
}
DebugMsg("%s\n", str);
fp = (volatile FILE *) POpen(str, "r", 0);
if (fp != NULL) {
if (setjmp(gLocalListJmp) == 0) {
/* Command was not interrupted. */
si = SIGNAL(SIGINT, SigLocalList);
sp = SIGNAL(SIGPIPE, SigLocalList);
MultiLineInit();
while (fgets(str, ((int) sizeof(str)) - 1, (FILE *)fp) != NULL)
MultiLinePrintF("%s", str);
}
(void) SIGNAL(SIGINT, SIG_IGN);
(void) SIGNAL(SIGPIPE, SIG_IGN);
PClose((FILE *) fp);
}
if (si != (VSig_t) kNoSignalHandler)
(void) SIGNAL(SIGINT, si);
if (sp != (VSig_t) kNoSignalHandler)
(void) SIGNAL(SIGPIPE, sp);
return (kNoErr);
} /* LocalListCmd */
int RedirCmd(int argcUNUSED, char **argv)
{
LinePtr lp;
volatile FILE *pager;
VSig_t si, sp;
si = (VSig_t) kNoSignalHandler;
sp = (VSig_t) kNoSignalHandler;
if (argv[0][0] == 'p') {
/* If the command started with 'p' we should be paging this. */
if (gPager[0] == '\0') {
EPrintF("You haven't specified a program to use as a pager.\n");
EPrintF("You can set this from the preferences screen (prefs command).\n");
return (-1);
}
pager = (volatile FILE *) POpen(gPager, "w", 1);
if (pager == NULL) {
Error(kDoPerror, "Could not open: %s\n", gPager);
return (-1);
}
if (setjmp(gPDirJmp) == 0) {
/* Command was not interrupted. */
sp = SIGNAL(SIGPIPE, PDirHandler);
si = SIGNAL(SIGINT, PDirHandler);
for (lp = gRedir.first; lp != NULL; lp = lp->next)
fprintf((FILE *) pager, "%s\n", lp->line);
PClose((FILE *) pager);
RestoreScreen(1);
}
} else {
MultiLineInit();
for (lp = gRedir.first; lp != NULL; lp = lp->next)
MultiLinePrintF("%s\n", lp->line);
}
if (si != (VSig_t) kNoSignalHandler)
(void) SIGNAL(SIGINT, si);
if (sp != (VSig_t) kNoSignalHandler)
(void) SIGNAL(SIGPIPE, sp);
return (kNoErr);
} /* RedirCmd */
syntax highlighted by Code2HTML, v. 0.9.1