/*****************************************************************************\
* Copyright (c) 2002-2004 Pelle Johansson. *
* All rights reserved. *
* *
* This file is part of the moftpd package. Use and distribution of *
* this software is governed by the terms in the file LICENCE, which *
* should have come with this package. *
\*****************************************************************************/
/* $moftpd: com_info.c 1245 2004-12-09 12:01:59Z morth $ */
#include "system.h"
#include "commands.h"
#include "connection.h"
#include "utf8fs/memory.h"
extern const command_t commands[], siteCommands[];
extern const int numCommands, numSiteCommands;
extern const char *localeDir;
extern const char *localeSuffix;
/* Informational commands */
int command_syst(connection_t *conn, const char *arg, int expected)
{
reply(conn, "215 UNIX system type.");
return 0;
}
int command_stat(connection_t *conn, const char *arg, int expected)
{
if(conn->working)
{
if(conn->data)
reply(conn, "213 Sent %llu of %llu bytes.",
conn->dataOffset - conn->restart, conn->dataLen - conn->restart);
else if(conn->sending)
reply(conn, "213 Sent %llu bytes.", conn->dataOffset);
else
reply(conn, "213 Received %llu bytes.", conn->dataOffset);
}
else
{
if(strlen(arg))
{
char *list = make_file_list(arg, conn->cwd, conn->user->home, 1, " ");
if(!list)
{
if(errno == ENOENT)
{
reply(conn, "500 No such file or directory.");
return 0;
}
reply(conn, "450 %s.", strerror(errno));
return 0;
}
reply (conn, "212-Listing of \"%s\":", arg);
send_telnet (conn, list, 0);
reply (conn, "212 End of listing.");
}
else
{
reply (conn, "211-Connection status:");
reply (conn, " Transfer type is %s.", conn->type == ttImage ?
conn->subtype? "Local 8" : "Image" :
conn->subtype? "Telnet Formatted Text" : "Non-Print Text");
reply (conn, " Transfer mode is Stream.");
reply (conn, " File structure is File.");
reply (conn, " Data connection is %s.", conn->dataSock >= 0 ?
!conn->passive || conn->passiveAccepted ? "open" :
"waiting for connect" : "closed");
reply (conn, "211 End of status.");
}
}
return 0;
}
int command_help(connection_t *conn, const char *arg, int expected)
{
/* gcc says spbuf is variable-sized if I just const int. */
#define cwidth 6
const int columns = 80 / cwidth;
const int rows = (numCommands + columns - 1) / columns;
const command_t *comm[columns];
int i, j;
char line[81], *lend;
if (!strncasecmp (arg, "SITE", 4) && (!arg[4] || arg[4] == ' '))
{
if (!arg[4])
return sitecommand_help (conn, "", 0);
return sitecommand_help (conn, arg + 5, 0);
}
if (arg[0])
{
for (comm[0] = commands; comm[0]->name; comm[0]++)
{
if (!strcasecmp (arg, comm[0]->name))
{
if (comm[0]->help)
reply (conn, "214 %s%s", comm[0]->name, comm[0]->help);
else
reply (conn, "214 %s: No help is available.", comm[0]->name);
return 0;
}
}
reply (conn, "500 No such command %s.", arg);
return 0;
}
reply(conn, "214-These commands are recognised:");
for(i = 0; i < columns; i++)
{
if (rows * i < numCommands)
comm[i] = &commands[rows * i];
else
comm[i] = &commands[numCommands];
}
while(comm[0] != &commands[rows])
{
strcpy (line, " ");
lend = line + 1;
for(i = 0; i < columns; i++)
{
if(comm[i]->name)
{
strcpy (lend, comm[i]->name);
j = strlen (lend);
lend += j;
for (; j < cwidth; j++)
*lend++ = ' ';
comm[i]++;
}
else
break;
}
*lend = 0;
reply (conn, "%s", line);
}
reply(conn, "214 End of help.");
return 0;
#undef cwidth
}
int sitecommand_help(connection_t *conn, const char *arg, int expected)
{
/* gcc says spbuf is variable-sized if I just const int. */
#define cwidth 7
const int columns = 80 / cwidth;
const int rows = (numSiteCommands + columns - 1) / columns;
const command_t *comm[columns];
int i, j;
char line[81], *lend;
if (arg[0])
{
for (comm[0] = siteCommands; comm[0]->name; comm[0]++)
{
if (!strcasecmp (arg, comm[0]->name))
{
if (comm[0]->help)
reply (conn, "214 SITE %s%s", comm[0]->name, comm[0]->help);
else
reply (conn, "214 SITE %s: No help is available.", comm[0]->name);
return 0;
}
}
reply (conn, "500 No such command SITE %s.", arg);
return 0;
}
reply (conn, "214-These SITE commands are recognised:");
for (i = 0; i < columns; i++)
{
if (rows * i < numSiteCommands)
comm[i] = &siteCommands[rows * i];
else
comm[i] = &siteCommands[numSiteCommands];
}
while (comm[0] != &siteCommands[rows])
{
strcpy (line, " ");
lend = line + 1;
for (i = 0; i < columns; i++)
{
if (comm[i]->name)
{
strcpy (lend, comm[i]->name);
j = strlen (lend);
lend += j;
for (; j < cwidth; j++)
*lend++ = ' ';
comm[i]++;
}
else
break;
}
*lend = 0;
reply (conn, "%s", line);
}
reply (conn, "214 End of help.");
return 0;
#undef cwidth
}
int command_feat (connection_t *conn, const char *arg, int expected)
{
DIR *locDir;
struct dirent *dp;
char *ltxt, *suff, *lp, *np;
int i;
reply (conn, "211-These features are supported.");
//reply (conn, " ADAT");
reply (conn, " AUTH"
#ifdef USE_TLS
" TLS"
#endif
);
reply (conn, " CCC");
//reply (conn, " CONF");
//reply (conn, " ENC");
reply (conn, " EPRT");
reply (conn, " EPSV");
reply (conn, " HOST");
if ((locDir = opendir (localeDir)))
{
ltxt = talloc (4);
if (ltxt)
{
strcpy (ltxt, "EN");
lp = ltxt + 2;
if (!conn->currLang)
*lp++ = '*';
i = 0;
while ((dp = readdir (locDir)))
{
if (dp->d_name[0] == '.')
continue;
suff = strstr (dp->d_name, localeSuffix);
if (!suff || strlen (suff) != strlen (localeSuffix))
continue;
ltxt = trealloc (ltxt, lp - ltxt + suff - dp->d_name + 3);
if (!ltxt)
break;
lp = ltxt + strlen (ltxt);
*lp++ = ';';
for (np = dp->d_name; np != suff; np++)
*lp++ = toupper (*np);
if (conn->currLang && !strncmp (dp->d_name, conn->currLang, suff - dp->d_name))
{
*lp++ = '*';
i = 1;
}
}
if (ltxt && !i && conn->currLang)
{
ltxt = trealloc (ltxt, lp - ltxt + strlen (conn->currLang) + 3);
if (ltxt)
{
*lp++ = ';';
for (np = conn->currLang; *np; np++)
*lp++ = toupper (*np);
*lp++ = '*';
}
}
if (ltxt)
{
*lp = 0;
reply (conn, " LANG %s", ltxt);
}
}
closedir (locDir);
}
else
reply (conn, " LANG EN*");
reply (conn, " LPRT");
reply (conn, " LPSV");
reply (conn, " MDTM");
reply (conn, " MFMT");
//reply (conn, " MIC");
reply (conn, " MLST TYPE%s;UNIQUE%s;MODIFY%s;PERM%s;SIZE%s;",
conn->mlstTags & tfType? "*" : "", conn->mlstTags & tfUnique? "*" : "",
conn->mlstTags & tfModify? "*" : "", conn->mlstTags & tfPerm? "*" : "",
conn->mlstTags & tfSize? "*" : "");
reply (conn, " PBSZ");
reply (conn, " PROT");
reply (conn, " REST STREAM");
reply (conn, " SIZE");
reply (conn, " TVFS");
reply (conn, " UTF8");
reply (conn, "211 End of features list.");
return 0;
}
int sitecommand_ftpd (connection_t *conn, const char *arg, int expected)
{
reply (conn, "200-%s, Copyright ® 2002-2004 Pelle Johansson", PACKAGE_STRING);
reply (conn, "200-%s comes with ABSOLUTELY NO WARRANTY", PACKAGE_NAME);
reply (conn, "200-This is free software, and you are welcome to redistribute ");
reply (conn, "200-it under certain conditions.");
reply (conn, "200 See the GNU GPL available at http://www.gnu.org/ for details.");
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1