📄 nap.c
字号:
/* Copyright (c) 2000 Kevin Sullivan <nite@gis.net> * * Please refer to the COPYRIGHT file for more information. */#ifdef HAVE_CONFIG_H# include <config.h>#endif#define _GNU_SOURCE /* needed for stdio.h:vasprintf */#include <stdio.h>#include <time.h>#include <stdarg.h>#include <termios.h>#include <dirent.h>#include <fcntl.h>#include <sys/types.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/wait.h>#include <utime.h>#include <ncurses.h>#include <stdlib.h>#include <signal.h>#include <string.h>#include <ctype.h>#include <unistd.h>#include <sys/stat.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <sys/time.h>#include <netdb.h>#include <errno.h>#include "getopt.h"#include "defines.h"#include "codes.h"#include "colors.h"#include "title.h"#include "alias.h"#include "event.h"#include "handlers.h"#include "lists.h"#include "nap.h"#include "scheck.h"#include "winio.h"#include "missing.h"#ifdef MEMWATCH #include "memwatch.h"#endif/* standard napster servers */extern int ircin;extern int ircsock;extern int ups[], speeds[];extern char cbuf[];extern upload_t *up;extern download_t *down;chans_t *chanl = NULL, *curchan = NULL;hotlist_t *hlist = NULL;info_t info; /* struct to hold some command line options */int cloaked = 0; /* whether we are cloaked */int lpbrk=0, noresolv=0, reconnect=0;int ipcs[2];int dresize = 0;void doquit(){ scrollbottom(); if (wchan) { dscr(wchan); drw(wchan); } if (ircin) { ssock(ircsock, "QUIT :Leaving\n"); close(ircsock); ircsock = 0; } if (nvar_default("savechannels", 0)) { char *tmp = NULL, *fn; msprintf(&tmp, CHANNELFILE, info.user); fn = home_file(tmp); free(tmp); if (savechans(chanl, fn)==-1) { wp(wchan, ""RED"* Could not save channels to %s: %s"WHITE"\n", fn, \ strerror(errno)); } else { wp(wchan, "* Saved channels to %s\n", fn); } free(fn); } /* close incomplete files, remove turds, etc */ while (up) dupload(up); while (down) ddownload(wchan, down); endwin(); exit(1);}void tresize(int dummy){ dresize = 1;}/* catch interrupt signal, i.e. usually "Control-C". In interactive mode, quit program only after receiving two interrupts within one second. Interrupt also causes a "while" loop to be broken - see dwhile in cmds.c */void sigint(int dummy){ int save_errno = errno; static time_t cct = 0; if ((time(NULL)-cct) <= 1) doquit(); cct = time(NULL); lpbrk = 1; errno = save_errno;}/* the following is used as a signal "handler" if we just want the signal to cause a side effect, such as interrupting sleep(3) */void noop(int dummy){ /* empty */}/* handle the USR1 signal. This should schedule the "reconnect" command. */void sigusr1(int dummy){ reconnect = 1;} void dochecks(){ if (dresize) { dresize = 0; resize(); }}/* quotes a string so that it is printable. Each call frees the previously returned value. */char *quote(char *s) { static char *buf = NULL; int i, size; if (buf) { free(buf); } size = strlen(s) * 1.2; buf = (char *)malloc(size); for (i=0; *s != 0; s++) { if (i>size-10) { size += 100; buf = (char *)realloc(buf, size); } if (32 <= *s && *s < 127) { /* printable ASCII */ buf[i++] = *s; } else if (*s == '\n') { i += sprintf(&buf[i], "\\n"); } else if (*s == '\r') { i += sprintf(&buf[i], "\\r"); } else { i += sprintf(&buf[i], "\\%03o", (unsigned char)*s); } } buf[i] = 0; return buf;}/* returns the full path of file fn relative to user's home directory. Always returns an allocated string. */char *home_file(const char *fn) { char *home, *res; int len; if (fn[0] == '/') /* absolute filename? */ return strdup(fn); if (0==strncmp(fn,"~/",2)) /* handle also ~/ syntax - dz */ fn += 2; home = getenv("HOME"); /* else, try to find home directory */ if (!home) return strdup(fn); len = strlen(home); res = (char *)malloc(len+strlen(fn)+2); strcpy(res, home); if (home[len-1] != '/') strcat(res, "/"); strcat(res, fn); return res;}/* make a an allocated string from an integer, similar to strdup */char *itoa(int n) { char buf[20]; sprintf(buf, "%d", n); return strdup(buf);}/* strip whitespace from both ends of a string, descructively */char *strip(char *s) { char *p; if (!s) return NULL; while (isspace(*s)) { s++; } p = s+strlen(s); while (p>s && isspace(p[-1])) p--; *p = 0; return s;}/* read an allocated, stripped line from stream. Return NULL on eof or error. */char *nap_getline(FILE *f) { char *buf; char *res; int size; /* current allocated size of buf */ int l; size = 200; /* should be large enough to hold an average line from * the shared library without having to realloc() the * buffer */ buf = (char *)malloc(size); res = fgets(buf, size, f); if (!res) { /* end of file */ free(buf); return NULL; } while (!strchr(buf, '\n')) { size *= 2; buf = (char *)realloc(buf, size); l = strlen(buf); res = fgets(buf+l, size-l, f); if (!res) /* end of file */ break; } /* strip whitespace from both ends */ res = strdup(strip(buf)); free(buf); return res;}/* Read the config file FN. Values that were given on the command line override those in the config file - don't read them. Note: if user was specified on the command line, take special care *not* to use password and email address from config file. FN must be a non-null filename. Return 0. */int readcfg(char *fn) { int other_user = 0; char *user=NULL, *pass=NULL, *email=NULL; int r; struct stat st; char *gfn; if (getval("user")) { /* user was specified on command line - do not use password or email from config file */ other_user = 1; user = strdup(getval("user")); pass = getrealval("pass"); if (pass) pass = strdup(pass); email = getval("email"); if (email) email = strdup(email); } /* read the config file - but in a wimpy way that does not overwrite existing values. This is because command line values should have priority. */ wp(NULL, "Reading user config file %s...\n", fn); r = loadsets(fn, NULL, 0, 0); if (r==0) { /* success */ } else if (r==1) { wp(NULL, "There were some warnings, please edit your config file.\n"); } else if (errno == ENOENT) { /* no such file or directory */ wp(NULL, "%s: file not found.\n", fn); } else { wp(NULL, "Error loading config file %s: %s\n", fn, strerror(errno)); } /* read the global config file, if any. Note that this is read *last*. I.e., the values given there are the *least* authoritative. */ gfn = getval("globalconfigfile"); if (!gfn) { gfn = GLOBALCONFIGFILE; } if (gfn) { r = stat(gfn, &st); if (r==0 && S_ISREG(st.st_mode)) { /* only if file exists and is regular */ wp(NULL, "Reading global config file %s...\n", gfn); r = loadsets(gfn, NULL, 0, 0); if (r==0) { /* success */ } else if (r==1) { wp(NULL, "There were some warnings, please edit global config file.\n"); } else if (errno == ENOENT) { /* no such file or directory */ wp(NULL, "%s: file not found.\n", gfn); } else { wp(NULL, "Error loading global config file %s: %s\n", gfn, strerror(errno)); } } } /* restore password and email if necessary */ if (other_user) { chset("user", user); chset("pass", pass); chset("email", email); free(user); free(pass); free(email); } return 0;}/* Try to guess reasonable defaults for vital configuration variables. Where appropriate, prompt the user. Return -1 if the user refused to supply a username or password, else 0. FN must be a non-null filename for the config file to be created / updated. If FN is null, nothing will be written to a file. Note: if info.daemon is set, then we never prompt the user for anything, and supply defaults as we can. */int set_defaults_interactive(char *fn) { int changes = 0; char *ans; char *user, *pass; int conn; int r; struct stat st; int userprompt = 0; ans = NULL; if (!getval("user")) { if (!info.daemon) { userprompt = 1; wp(NULL, "User: "); ans = nap_getline(stdin); } if (!ans || !*ans) { wp(NULL, "No user name given\n"); free(ans); return(-1); } else { chset("user", ans); changes = 1; } } free(ans); ans = NULL; user = getval("user"); pass = getrealval("pass"); /* note: getval("pass") does not work - it always returns "?" */ /* if password not defined, check the variable pass.<user> */ if (!pass || !strcmp(pass, "?")) { char tmp[10+strlen(user)]; strcpy(tmp, "pass."); strcat(tmp, user); pass = getval(tmp); if (pass) { chset("pass", pass); } } if (!pass || !strcmp(pass,"?")) { if (userprompt) { wp(NULL, "Password for user %s (optional): ", user); ans = getpass(""); /* note: getpass(3) does not allocate its result value, thus we should not free it. */ } if (ans && *ans) { chset("pass", ans); } } ans = NULL; pass = getrealval("pass"); if (!pass || !strcmp(pass, "?")) { char pw[9]; struct timeval tv; int i; gettimeofday(&tv, NULL); srand(tv.tv_usec + 1000000*tv.tv_sec); for (i=0; i<8; i++) { pw[i] = rand() % 26 + 'a'; } pw[8] = 0; chset("pass", pw); wp(NULL, "No password given - using random password\n"); } /* if email not defined, check the variable email.<user> */ if (!getval("email")) { char *email; char tmp[10+strlen(user)]; strcpy(tmp, "email."); strcat(tmp, user); email = getval(tmp); if (email) { chset("email", email); } } if (!getval("email")) { if (userprompt) { wp(NULL, "Email for user %s (optional): ", user); ans = nap_getline(stdin); } if (ans && *ans) { chset("email", ans); changes = 1; } free(ans); ans = NULL; } if (!getval("email")) { chset("email", "anon@localhost"); wp(NULL, "No email given - using anon@localhost\n"); } if (!getval("upload")) { if (!info.daemon) { wp(NULL, "Please enter a list of directories with files that you want to share.\n"); wp(NULL, "You can enter several directories, separated by semicolons (';').\n"); wp(NULL, "Upload path: "); ans = nap_getline(stdin); } if (!ans || !*ans) { wp(NULL, "No upload directories given - unable to share files\n"); } else { chset("upload", ans); changes = 1; } } free(ans); ans = NULL; if (!getval("download")) { if (!info.daemon) { wp(NULL, "Please enter the directory where you want to put downloaded files.\n"); wp(NULL, "Download directory: "); ans = nap_getline(stdin); } if (!ans || !*ans) { wp(NULL, "No download directory given - will use current working directory\n"); } else { chset("download", ans); changes = 1; } } free(ans); ans = NULL; if (!getval("incomplete")) { if (!info.daemon) { wp(NULL, "Please enter the directory where you want to put incomplete files.\n"); wp(NULL, "Incomplete directory: "); ans = nap_getline(stdin); } if (!ans || !*ans) { wp(NULL, "No incomplete directory given - will use download directory\n"); } else { chset("incomplete", ans); changes = 1; } } free(ans); ans = NULL; if (!getval("dataport")) { if (!info.daemon) { wp(NULL, "Are you behind a firewall? [y=yes, n=no, u=unsure]: "); ans = nap_getline(stdin); if (ans && ans[0]=='y') { wp(NULL, "Firewalled client - setting dataport to 0\n"); chset("dataport", "0"); } else if (ans && ans[0]=='n') { wp(NULL, "Using dataport 6699-6799\n"); chset("dataport", "6699-6799"); } else { wp(NULL, "Okay, I will assume that you are not firewalled. If you\n" "find out later that you are, please set your dataport to 0.\n"); wp(NULL, "Using dataport 6699-6799\n"); chset("dataport", "6699-6799"); } } else { chset("dataport", "6699-6799"); wp(NULL, "No dataport given - using %s\n", getval("dataport")); } } free(ans); ans = NULL; if (!getval("connection")) { if (!info.daemon) { wp(NULL, " Connection | Number\n" " -------------------\n" " Unknown | 0\n" " 14.4 | 1\n" " 28.8 | 2\n" " 33.6 | 3\n" " 56.7 | 4\n" " 64K ISDN | 5\n" " 128K ISDN | 6\n" " Cable | 7\n" " DSL | 8\n" " T1 | 9\n" " T3 or > | 10\n" ); wp(NULL, "How fast is your internet connection?\n"); wp(NULL, "Please choose 0--10 from the chart: [4] "); ans = nap_getline(stdin); } if (!ans || !*ans) { chset("connection", "4"); changes = 1; } else { chset("connection", ans);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -