/*****************************************************************************\ * 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; }