00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #define MODULE_NAME "filesys"
00027 #define MAKING_FILESYS
00028
00029 #include <fcntl.h>
00030 #include <sys/stat.h>
00031 #include <sys/file.h>
00032
00033 #include "src/mod/module.h"
00034
00035 #ifdef HAVE_DIRENT_H
00036 # include <dirent.h>
00037 # define NAMLEN(dirent) strlen((dirent)->d_name)
00038 #else
00039 # define dirent direct
00040 # define NAMLEN(dirent) (dirent)->d_namlen
00041 # ifdef HAVE_SYS_NDIR_H
00042 # include <sys/ndir.h>
00043 # endif
00044 # ifdef HAVE_SYS_DIR_H
00045 # include <sys/dir.h>
00046 # endif
00047 # ifdef HAVE_NDIR_H
00048 # include <ndir.h>
00049 # endif
00050 #endif
00051
00052 #ifdef TIME_WITH_SYS_TIME
00053 # include <sys/time.h>
00054 # include <time.h>
00055 #else
00056 # ifdef HAVE_SYS_TIME_H
00057 # include <sys/time.h>
00058 # else
00059 # include <time.h>
00060 # endif
00061 #endif
00062
00063 #include "filedb3.h"
00064 #include "filesys.h"
00065 #include "src/tandem.h"
00066 #include "files.h"
00067 #include "dbcompat.h"
00068 #include "filelist.h"
00069
00070 static p_tcl_bind_list H_fil;
00071 static Function *transfer_funcs = NULL;
00072
00073 #undef global
00074 static Function *global = NULL;
00075
00076
00077 static char dccdir[121] = "";
00078
00079
00080 static char dccin[121] = "";
00081
00082
00083 static int upload_to_cd = 0;
00084
00085
00086
00087 static int dcc_maxsize = 1024;
00088
00089
00090 static int dcc_users = 0;
00091
00092
00093
00094 static char filedb_path[121] = "";
00095
00096
00097 static int is_valid();
00098 static void eof_dcc_files(int idx);
00099 static void dcc_files(int idx, char *buf, int i);
00100 static void disp_dcc_files(int idx, char *buf);
00101 static int expmem_dcc_files(void *x);
00102 static void kill_dcc_files(int idx, void *x);
00103 static void out_dcc_files(int idx, char *buf, void *x);
00104 static char *mktempfile(char *filename);
00105
00106 static struct dcc_table DCC_FILES = {
00107 "FILES",
00108 DCT_MASTER | DCT_VALIDIDX | DCT_SHOWWHO | DCT_SIMUL | DCT_CANBOOT | DCT_FILES,
00109 eof_dcc_files,
00110 dcc_files,
00111 NULL,
00112 NULL,
00113 disp_dcc_files,
00114 expmem_dcc_files,
00115 kill_dcc_files,
00116 out_dcc_files
00117 };
00118
00119 static struct user_entry_type USERENTRY_DCCDIR = {
00120 NULL,
00121 NULL,
00122 NULL,
00123 NULL,
00124 NULL,
00125 NULL,
00126 NULL,
00127 NULL,
00128 NULL,
00129 NULL,
00130 NULL,
00131 NULL,
00132 NULL,
00133 "DCCDIR"
00134 };
00135
00136 #include "files.c"
00137 #include "filedb3.c"
00138 #include "tclfiles.c"
00139 #include "dbcompat.c"
00140 #include "filelist.c"
00141
00142
00143
00144
00145 static int check_tcl_fil(char *cmd, int idx, char *args)
00146 {
00147 int x;
00148 char s[5];
00149 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00150
00151 get_user_flagrec(dcc[idx].user, &fr, dcc[idx].u.file->chat->con_chan);
00152 sprintf(s, "%ld", dcc[idx].sock);
00153 Tcl_SetVar(interp, "_fil1", dcc[idx].nick, 0);
00154 Tcl_SetVar(interp, "_fil2", s, 0);
00155 Tcl_SetVar(interp, "_fil3", args, 0);
00156 x = check_tcl_bind(H_fil, cmd, &fr, " $_fil1 $_fil2 $_fil3",
00157 MATCH_PARTIAL | BIND_USE_ATTR | BIND_HAS_BUILTINS);
00158 if (x == BIND_AMBIGUOUS) {
00159 dprintf(idx, "Ambiguous command.\n");
00160 return 0;
00161 }
00162 if (x == BIND_NOMATCH) {
00163 dprintf(idx, "What? You need 'help'\n");
00164 return 0;
00165 }
00166
00167
00168 if (x == BIND_QUIT)
00169 return 1;
00170
00171 if (x == BIND_EXEC_LOG)
00172 putlog(LOG_FILES, "*", "#%s# files: %s %s", dcc[idx].nick, cmd, args);
00173 return 0;
00174 }
00175
00176 static void dcc_files_pass(int idx, char *buf, int x)
00177 {
00178 struct userrec *u = get_user_by_handle(userlist, dcc[idx].nick);
00179
00180 if (!x)
00181 return;
00182 if (u_pass_match(u, buf)) {
00183 if (too_many_filers()) {
00184 dprintf(idx, "Too many people are in the file system right now.\n");
00185 dprintf(idx, "Please try again later.\n");
00186 putlog(LOG_MISC, "*", "File area full: DCC chat [%s]%s", dcc[idx].nick,
00187 dcc[idx].host);
00188 killsock(dcc[idx].sock);
00189 lostdcc(idx);
00190 return;
00191 }
00192 dcc[idx].type = &DCC_FILES;
00193 if (dcc[idx].status & STAT_TELNET)
00194 dprintf(idx, "\377\374\001\n");
00195 putlog(LOG_FILES, "*", "File system: [%s]%s/%d", dcc[idx].nick,
00196 dcc[idx].host, dcc[idx].port);
00197 if (!welcome_to_files(idx)) {
00198 putlog(LOG_FILES, "*", "File system broken.");
00199 killsock(dcc[idx].sock);
00200 lostdcc(idx);
00201 } else {
00202 struct userrec *u = get_user_by_handle(userlist, dcc[idx].nick);
00203
00204 touch_laston(u, "filearea", now);
00205 }
00206 return;
00207 }
00208 dprintf(idx, "Negative on that, Houston.\n");
00209 putlog(LOG_MISC, "*", "Bad password: DCC chat [%s]%s", dcc[idx].nick,
00210 dcc[idx].host);
00211 killsock(dcc[idx].sock);
00212 lostdcc(idx);
00213 }
00214
00215
00216
00217 static int got_files_cmd(int idx, char *msg)
00218 {
00219 char *code;
00220
00221 strcpy(msg, check_tcl_filt(idx, msg));
00222 if (!msg[0])
00223 return 1;
00224 if (msg[0] == '.')
00225 msg++;
00226 code = newsplit(&msg);
00227 return check_tcl_fil(code, idx, msg);
00228 }
00229
00230 static void dcc_files(int idx, char *buf, int i)
00231 {
00232 if (buf[0] && detect_dcc_flood(&dcc[idx].timeval, dcc[idx].u.file->chat,
00233 idx))
00234 return;
00235 dcc[idx].timeval = now;
00236 strcpy(buf, check_tcl_filt(idx, buf));
00237 if (!buf[0])
00238 return;
00239 touch_laston(dcc[idx].user, "filearea", now);
00240 if (buf[0] == ',') {
00241 for (i = 0; i < dcc_total; i++) {
00242 if ((dcc[i].type->flags & DCT_MASTER) && dcc[idx].user &&
00243 (dcc[idx].user->flags & USER_MASTER) &&
00244 ((dcc[i].type == &DCC_FILES) || (dcc[i].u.chat->channel >= 0)) &&
00245 ((i != idx) || (dcc[idx].status & STAT_ECHO)))
00246 dprintf(i, "-%s- %s\n", dcc[idx].nick, &buf[1]);
00247 }
00248 } else if (got_files_cmd(idx, buf)) {
00249 dprintf(idx, "*** Ja mata!\n");
00250 flush_lines(idx, dcc[idx].u.file->chat);
00251 putlog(LOG_FILES, "*", "DCC user [%s]%s left file system", dcc[idx].nick,
00252 dcc[idx].host);
00253 set_user(&USERENTRY_DCCDIR, dcc[idx].user, dcc[idx].u.file->dir);
00254 if (dcc[idx].status & STAT_CHAT) {
00255 struct chat_info *ci;
00256
00257 dprintf(idx, "Returning you to command mode...\n");
00258 ci = dcc[idx].u.file->chat;
00259 my_free(dcc[idx].u.file);
00260 dcc[idx].u.chat = ci;
00261 dcc[idx].status &= (~STAT_CHAT);
00262 dcc[idx].type = &DCC_CHAT;
00263 if (dcc[idx].u.chat->channel >= 0) {
00264 chanout_but(-1, dcc[idx].u.chat->channel,
00265 "*** %s has returned.\n", dcc[idx].nick);
00266 if (dcc[idx].u.chat->channel < GLOBAL_CHANS)
00267 botnet_send_join_idx(idx, -1);
00268 }
00269 } else {
00270 dprintf(idx, "Dropping connection now.\n");
00271 putlog(LOG_FILES, "*", "Left files: [%s]%s/%d", dcc[idx].nick,
00272 dcc[idx].host, dcc[idx].port);
00273 killsock(dcc[idx].sock);
00274 lostdcc(idx);
00275 }
00276 }
00277 if (dcc[idx].status & STAT_PAGE)
00278 flush_lines(idx, dcc[idx].u.file->chat);
00279 }
00280
00281 static void tell_file_stats(int idx, char *hand)
00282 {
00283 struct userrec *u;
00284 struct filesys_stats *fs;
00285 float fr = (-1.0), kr = (-1.0);
00286
00287 u = get_user_by_handle(userlist, hand);
00288 if (u == NULL)
00289 return;
00290 if (!(fs = get_user(&USERENTRY_FSTAT, u))) {
00291 dprintf(idx, "No file statistics for %s.\n", hand);
00292 } else {
00293 dprintf(idx, " uploads: %4u / %6luk\n", fs->uploads, fs->upload_ks);
00294 dprintf(idx, "downloads: %4u / %6luk\n", fs->dnloads, fs->dnload_ks);
00295 if (fs->uploads)
00296 fr = ((float) fs->dnloads / (float) fs->uploads);
00297 if (fs->upload_ks)
00298 kr = ((float) fs->dnload_ks / (float) fs->upload_ks);
00299 if (fr < 0.0)
00300 dprintf(idx, "(infinite file leech)\n");
00301 else
00302 dprintf(idx, "leech ratio (files): %6.2f\n", fr);
00303 if (kr < 0.0)
00304 dprintf(idx, "(infinite size leech)\n");
00305 else
00306 dprintf(idx, "leech ratio (size) : %6.2f\n", kr);
00307 }
00308 }
00309
00310 static int cmd_files(struct userrec *u, int idx, char *par)
00311 {
00312 int atr = u ? u->flags : 0;
00313 static struct chat_info *ci;
00314
00315 if (dccdir[0] == 0)
00316 dprintf(idx, "There is no file transfer area.\n");
00317 else if (too_many_filers()) {
00318 dprintf(idx, "The maximum of %d %s in the file area right now.\n",
00319 dcc_users, (dcc_users != 1) ? "people are" : "person is");
00320 dprintf(idx, "Please try again later.\n");
00321 } else {
00322 if (!(atr & (USER_MASTER | USER_XFER)))
00323 dprintf(idx, "You don't have access to the file area.\n");
00324 else {
00325 putlog(LOG_CMDS, "*", "#%s# files", dcc[idx].nick);
00326 dprintf(idx, "Entering file system...\n");
00327 if (dcc[idx].u.chat->channel >= 0) {
00328
00329 chanout_but(-1, dcc[idx].u.chat->channel,
00330 "*** %s has left: file system\n", dcc[idx].nick);
00331 if (dcc[idx].u.chat->channel < GLOBAL_CHANS)
00332 botnet_send_part_idx(idx, "file system");
00333 }
00334 ci = dcc[idx].u.chat;
00335 dcc[idx].u.file = get_data_ptr(sizeof(struct file_info));
00336
00337 dcc[idx].u.file->chat = ci;
00338 dcc[idx].type = &DCC_FILES;
00339 dcc[idx].status |= STAT_CHAT;
00340 if (!welcome_to_files(idx)) {
00341 struct chat_info *ci = dcc[idx].u.file->chat;
00342
00343 my_free(dcc[idx].u.file);
00344 dcc[idx].u.chat = ci;
00345 dcc[idx].type = &DCC_CHAT;
00346 putlog(LOG_FILES, "*", "File system broken.");
00347 if (dcc[idx].u.chat->channel >= 0) {
00348 chanout_but(-1, dcc[idx].u.chat->channel,
00349 "*** %s has returned.\n", dcc[idx].nick);
00350 if (dcc[idx].u.chat->channel < GLOBAL_CHANS)
00351 botnet_send_join_idx(idx, -1);
00352 }
00353 } else
00354 touch_laston(u, "filearea", now);
00355 }
00356 }
00357 return 0;
00358 }
00359
00360 static int _dcc_send(int idx, char *filename, char *nick, char *dir,
00361 int resend)
00362 {
00363 int x;
00364 char *nfn, *buf = NULL;
00365
00366 if (strlen(nick) > NICKMAX)
00367 nick[NICKMAX] = 0;
00368 if (resend)
00369 x = raw_dcc_resend(filename, nick, dcc[idx].nick, dir);
00370 else
00371 x = raw_dcc_send(filename, nick, dcc[idx].nick, dir);
00372 if (x == DCCSEND_FULL) {
00373 dprintf(idx, "Sorry, too many DCC connections. (try again later)\n");
00374 putlog(LOG_FILES, "*", "DCC connections full: %sGET %s [%s]", filename,
00375 resend ? "RE" : "", dcc[idx].nick);
00376 return 0;
00377 }
00378 if (x == DCCSEND_NOSOCK) {
00379 if (reserved_port_min) {
00380 dprintf(idx, "All my DCC SEND ports are in use. Try later.\n");
00381 putlog(LOG_FILES, "*", "DCC port in use (can't open): %sGET %s [%s]",
00382 resend ? "RE" : "", filename, dcc[idx].nick);
00383 } else {
00384 dprintf(idx, "Unable to listen at a socket.\n");
00385 putlog(LOG_FILES, "*", "DCC socket error: %sGET %s [%s]", filename,
00386 resend ? "RE" : "", dcc[idx].nick);
00387 }
00388 return 0;
00389 }
00390 if (x == DCCSEND_BADFN) {
00391 dprintf(idx, "File not found ?\n");
00392 putlog(LOG_FILES, "*", "DCC file not found: %sGET %s [%s]", filename,
00393 resend ? "RE" : "", dcc[idx].nick);
00394 return 0;
00395 }
00396 if (x == DCCSEND_FEMPTY) {
00397 dprintf(idx, "The file is empty. Aborted transfer.\n");
00398 putlog(LOG_FILES, "*", "DCC file is empty: %s [%s]", filename,
00399 dcc[idx].nick);
00400 return 0;
00401 }
00402 nfn = strrchr(dir, '/');
00403 if (nfn == NULL)
00404 nfn = dir;
00405 else
00406 nfn++;
00407
00408
00409 if (strchr(nfn, ' ')) {
00410 char *p;
00411
00412 malloc_strcpy(buf, nfn);
00413 p = nfn = buf;
00414 while ((p = strchr(p, ' ')) != NULL)
00415 *p = '_';
00416 }
00417
00418 if (egg_strcasecmp(nick, dcc[idx].nick))
00419 dprintf(DP_HELP, "NOTICE %s :Here is %s file from %s %s...\n", nick,
00420 resend ? "the" : "a", dcc[idx].nick, resend ? "again " : "");
00421 dprintf(idx, "%sending: %s to %s\n", resend ? "Res" : "S", nfn, nick);
00422 my_free(buf);
00423 return 1;
00424 }
00425
00426 static int do_dcc_send(int idx, char *dir, char *fn, char *nick, int resend)
00427 {
00428 char *s = NULL, *s1 = NULL;
00429 int x;
00430
00431 if (nick && strlen(nick) > NICKMAX)
00432 nick[NICKMAX] = 0;
00433 if (dccdir[0] == 0) {
00434 dprintf(idx, "DCC file transfers not supported.\n");
00435 putlog(LOG_FILES, "*", "Refused dcc %sget %s from [%s]", resend ? "re" : "",
00436 fn, dcc[idx].nick);
00437 return 0;
00438 }
00439 if (strchr(fn, '/') != NULL) {
00440 dprintf(idx, "Filename cannot have '/' in it...\n");
00441 putlog(LOG_FILES, "*", "Refused dcc %sget %s from [%s]", resend ? "re" : "",
00442 fn, dcc[idx].nick);
00443 return 0;
00444 }
00445 if (dir[0]) {
00446 s = nmalloc(strlen(dccdir) + strlen(dir) + strlen(fn) + 2);
00447 sprintf(s, "%s%s/%s", dccdir, dir, fn);
00448 } else {
00449 s = nmalloc(strlen(dccdir) + strlen(fn) + 1);
00450 sprintf(s, "%s%s", dccdir, fn);
00451 }
00452
00453 if (!file_readable(s)) {
00454 dprintf(idx, "No such file.\n");
00455 putlog(LOG_FILES, "*", "Refused dcc %sget %s from [%s]", resend ? "re" :
00456 "", fn, dcc[idx].nick);
00457 my_free(s);
00458 return 0;
00459 }
00460
00461 if (!nick || !nick[0])
00462 nick = dcc[idx].nick;
00463
00464 if (at_limit(nick)) {
00465 char xxx[1024];
00466
00467 sprintf(xxx, "%d*%s%s", (int) strlen(dccdir), dccdir, dir);
00468 queue_file(xxx, fn, dcc[idx].nick, nick);
00469 dprintf(idx, "Queued: %s to %s\n", fn, nick);
00470 my_free(s);
00471 return 1;
00472 }
00473 if (copy_to_tmp) {
00474 char *tempfn = mktempfile(fn);
00475
00476
00477 s = nrealloc(s, strlen(dccdir) + strlen(dir) + strlen(fn) + 2);
00478 sprintf(s, "%s%s%s%s", dccdir, dir, dir[0] ? "/" : "", fn);
00479 s1 = nrealloc(s1, strlen(tempdir) + strlen(tempfn) + 1);
00480 sprintf(s1, "%s%s", tempdir, tempfn);
00481 my_free(tempfn);
00482 if (copyfile(s, s1) != 0) {
00483 dprintf(idx, "Can't make temporary copy of file!\n");
00484 putlog(LOG_FILES | LOG_MISC, "*",
00485 "Refused dcc %sget %s: copy to %s FAILED!",
00486 resend ? "re" : "", fn, tempdir);
00487 my_free(s);
00488 my_free(s1);
00489 return 0;
00490 }
00491 } else {
00492 s1 = nrealloc(s1, strlen(dccdir) + strlen(dir) + strlen(fn) + 2);
00493 sprintf(s1, "%s%s%s%s", dccdir, dir, dir[0] ? "/" : "", fn);
00494 }
00495 s = nrealloc(s, strlen(dir) + strlen(fn) + 2);
00496 sprintf(s, "%s%s%s", dir, dir[0] ? "/" : "", fn);
00497 x = _dcc_send(idx, s1, nick, s, resend);
00498 if (x != DCCSEND_OK)
00499 wipe_tmp_filename(s1, -1);
00500 my_free(s);
00501 my_free(s1);
00502 return x;
00503 }
00504
00505 static int builtin_fil STDVAR
00506 {
00507 int idx;
00508 Function F = (Function) cd;
00509
00510 BADARGS(4, 4, " hand idx param");
00511
00512 CHECKVALIDITY(builtin_fil);
00513 idx = findanyidx(atoi(argv[2]));
00514 if (idx < 0 && dcc[idx].type != &DCC_FILES) {
00515 Tcl_AppendResult(irp, "invalid idx", NULL);
00516 return TCL_ERROR;
00517 }
00518
00519
00520
00521
00522 if (F == CMD_LEAVE) {
00523 Tcl_AppendResult(irp, "break", NULL);
00524 return TCL_OK;
00525 }
00526
00527 F(idx, argv[3]);
00528 Tcl_ResetResult(irp);
00529 return TCL_OK;
00530 }
00531
00532 static void tout_dcc_files_pass(int i)
00533 {
00534 dprintf(i, "Timeout.\n");
00535 putlog(LOG_MISC, "*", "Password timeout on dcc chat: [%s]%s", dcc[i].nick,
00536 dcc[i].host);
00537 killsock(dcc[i].sock);
00538 lostdcc(i);
00539 }
00540
00541 static void disp_dcc_files(int idx, char *buf)
00542 {
00543 sprintf(buf, "file flags: %c%c%c%c%c",
00544 dcc[idx].status & STAT_CHAT ? 'C' : 'c',
00545 dcc[idx].status & STAT_PARTY ? 'P' : 'p',
00546 dcc[idx].status & STAT_TELNET ? 'T' : 't',
00547 dcc[idx].status & STAT_ECHO ? 'E' : 'e',
00548 dcc[idx].status & STAT_PAGE ? 'P' : 'p');
00549 }
00550
00551 static void disp_dcc_files_pass(int idx, char *buf)
00552 {
00553 long tv;
00554
00555 tv = now - dcc[idx].timeval;
00556 sprintf(buf, "fpas waited %lis", tv);
00557 }
00558
00559 static void kill_dcc_files(int idx, void *x)
00560 {
00561 register struct file_info *f = (struct file_info *) x;
00562
00563 if (f->chat)
00564 DCC_CHAT.kill(idx, f->chat);
00565 my_free(x);
00566 }
00567
00568 static void eof_dcc_files(int idx)
00569 {
00570 dcc[idx].u.file->chat->con_flags = 0;
00571 putlog(LOG_MISC, "*", "Lost dcc connection to %s (%s/%d)", dcc[idx].nick,
00572 dcc[idx].host, dcc[idx].port);
00573 killsock(dcc[idx].sock);
00574 lostdcc(idx);
00575 }
00576
00577 static int expmem_dcc_files(void *x)
00578 {
00579 register struct file_info *p = (struct file_info *) x;
00580 int tot = sizeof(struct file_info);
00581
00582 if (p->chat)
00583 tot += DCC_CHAT.expmem(p->chat);
00584 return tot;
00585 }
00586
00587 static void out_dcc_files(int idx, char *buf, void *x)
00588 {
00589 register struct file_info *p = (struct file_info *) x;
00590
00591 if (p->chat)
00592 DCC_CHAT.output(idx, buf, p->chat);
00593 else
00594 tputs(dcc[idx].sock, buf, strlen(buf));
00595 }
00596
00597 static cmd_t mydcc[] = {
00598 {"files", "-", cmd_files, NULL},
00599 {NULL, NULL, NULL, NULL}
00600 };
00601
00602 static tcl_strings mystrings[] = {
00603 {"files-path", dccdir, 120, STR_DIR | STR_PROTECT},
00604 {"incoming-path", dccin, 120, STR_DIR | STR_PROTECT},
00605 {"filedb-path", filedb_path, 120, STR_DIR | STR_PROTECT},
00606 {NULL, NULL, 0, 0}
00607 };
00608
00609 static tcl_ints myints[] = {
00610 {"max-filesize", &dcc_maxsize},
00611 {"max-file-users", &dcc_users},
00612 {"upload-to-pwd", &upload_to_cd},
00613 {NULL, NULL}
00614 };
00615
00616 static struct dcc_table DCC_FILES_PASS = {
00617 "FILES_PASS",
00618 0,
00619 eof_dcc_files,
00620 dcc_files_pass,
00621 NULL,
00622 tout_dcc_files_pass,
00623 disp_dcc_files_pass,
00624 expmem_dcc_files,
00625 kill_dcc_files,
00626 out_dcc_files
00627 };
00628
00629
00630 static void filesys_dcc_send_hostresolved(int);
00631
00632
00633
00634 static void filesys_dcc_send(char *nick, char *from, struct userrec *u,
00635 char *text)
00636 {
00637 char *param, *ip, *prt, *buf = NULL, *msg;
00638 int atr = u ? u->flags : 0, i, j = 0;
00639
00640 if (text[j] == '"') {
00641 text[j] = ' ';
00642
00643 for (j = 1; text[j] != '"' && text[j] != '\0'; j++) {
00644 if (text[j] == ' ')
00645 {
00646 text[j] = '_';
00647 }
00648 }
00649
00650 text[j] = ' ';
00651 }
00652
00653 buf = nmalloc(strlen(text) + 1);
00654 msg = buf;
00655 strcpy(buf, text);
00656 param = newsplit(&msg);
00657 if (!(atr & USER_XFER)) {
00658 putlog(LOG_FILES, "*", "Refused DCC SEND %s (no access): %s!%s", param,
00659 nick, from);
00660 if (!quiet_reject)
00661 dprintf(DP_HELP, "NOTICE %s :No access\n", nick);
00662 } else if (!dccin[0] && !upload_to_cd) {
00663 dprintf(DP_HELP, "NOTICE %s :DCC file transfers not supported.\n", nick);
00664 putlog(LOG_FILES, "*", "Refused dcc send %s from %s!%s", param, nick, from);
00665 } else if (strchr(param, '/')) {
00666 dprintf(DP_HELP, "NOTICE %s :Filename cannot have '/' in it...\n", nick);
00667 putlog(LOG_FILES, "*", "Refused dcc send %s from %s!%s", param, nick, from);
00668 } else {
00669 ip = newsplit(&msg);
00670 prt = newsplit(&msg);
00671 if (atoi(prt) < 1024 || atoi(prt) > 65535) {
00672
00673 dprintf(DP_HELP, "NOTICE %s :%s (invalid port)\n", nick,
00674 DCC_CONNECTFAILED1);
00675 putlog(LOG_FILES, "*", "Refused dcc send %s (%s): invalid port", param,
00676 nick);
00677 } else if (atoi(msg) == 0) {
00678 dprintf(DP_HELP, "NOTICE %s :Sorry, file size info must be included.\n",
00679 nick);
00680 putlog(LOG_FILES, "*", "Refused dcc send %s (%s): no file size",
00681 param, nick);
00682 } else if (dcc_maxsize && (atoi(msg) > (dcc_maxsize * 1024))) {
00683 dprintf(DP_HELP, "NOTICE %s :Sorry, file too large.\n", nick);
00684 putlog(LOG_FILES, "*", "Refused dcc send %s (%s): file too large", param,
00685 nick);
00686 } else {
00687
00688 if (!sanitycheck_dcc(nick, from, ip, prt)) {
00689 my_free(buf);
00690 return;
00691 }
00692 i = new_dcc(&DCC_DNSWAIT, sizeof(struct dns_info));
00693 if (i < 0) {
00694 dprintf(DP_HELP, "NOTICE %s :Sorry, too many DCC connections.\n", nick);
00695 putlog(LOG_MISC, "*", "DCC connections full: SEND %s (%s!%s)", param,
00696 nick, from);
00697 return;
00698 }
00699 dcc[i].addr = my_atoul(ip);
00700 dcc[i].port = atoi(prt);
00701 dcc[i].sock = -1;
00702 dcc[i].user = u;
00703 strcpy(dcc[i].nick, nick);
00704 strcpy(dcc[i].host, from);
00705 dcc[i].u.dns->cbuf = get_data_ptr(strlen(param) + 1);
00706 strcpy(dcc[i].u.dns->cbuf, param);
00707 dcc[i].u.dns->ibuf = atoi(msg);
00708 dcc[i].u.dns->ip = dcc[i].addr;
00709 dcc[i].u.dns->dns_type = RES_HOSTBYIP;
00710 dcc[i].u.dns->dns_success = filesys_dcc_send_hostresolved;
00711 dcc[i].u.dns->dns_failure = filesys_dcc_send_hostresolved;
00712 dcc[i].u.dns->type = &DCC_FORK_SEND;
00713 dcc_dnshostbyip(dcc[i].addr);
00714 }
00715 }
00716 my_free(buf);
00717 }
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727 #define MKTEMPFILE_TOT (7 + 2 + 8)
00728 static char *mktempfile(char *filename)
00729 {
00730 char rands[8], *tempname, *fn = filename;
00731 int l;
00732
00733 make_rand_str(rands, 7);
00734 l = strlen(filename);
00735 if ((l + MKTEMPFILE_TOT) > NAME_MAX) {
00736 fn[NAME_MAX - MKTEMPFILE_TOT] = 0;
00737 l = NAME_MAX - MKTEMPFILE_TOT;
00738 fn = nmalloc(l + 1);
00739 strncpy(fn, filename, l);
00740 fn[l] = 0;
00741 }
00742 tempname = nmalloc(l + MKTEMPFILE_TOT + 1);
00743 sprintf(tempname, "%u-%s-%s", getpid(), rands, fn);
00744 if (fn != filename)
00745 my_free(fn);
00746 return tempname;
00747 }
00748
00749 static void filesys_dcc_send_hostresolved(int i)
00750 {
00751 char *s1, *param, prt[100], ip[100], *tempf;
00752 int len = dcc[i].u.dns->ibuf, j;
00753
00754 sprintf(prt, "%d", dcc[i].port);
00755 sprintf(ip, "%lu", iptolong(htonl(dcc[i].addr)));
00756 if (!hostsanitycheck_dcc(dcc[i].nick, dcc[i].u.dns->host, dcc[i].addr,
00757 dcc[i].u.dns->host, prt)) {
00758 lostdcc(i);
00759 return;
00760 }
00761 param = nmalloc(strlen(dcc[i].u.dns->cbuf) + 1);
00762 strcpy(param, dcc[i].u.dns->cbuf);
00763
00764 changeover_dcc(i, &DCC_FORK_SEND, sizeof(struct xfer_info));
00765 if (param[0] == '.')
00766 param[0] = '_';
00767
00768 dcc[i].u.xfer->origname = get_data_ptr(strlen(param) + 1);
00769 strcpy(dcc[i].u.xfer->origname, param);
00770 tempf = mktempfile(param);
00771 dcc[i].u.xfer->filename = get_data_ptr(strlen(tempf) + 1);
00772 strcpy(dcc[i].u.xfer->filename, tempf);
00773
00774 my_free(tempf);
00775 my_free(param);
00776
00777 if (upload_to_cd) {
00778 char *p = get_user(&USERENTRY_DCCDIR, dcc[i].user);
00779
00780 if (p)
00781 sprintf(dcc[i].u.xfer->dir, "%s%s/", dccdir, p);
00782 else
00783 sprintf(dcc[i].u.xfer->dir, "%s", dccdir);
00784 } else
00785 strcpy(dcc[i].u.xfer->dir, dccin);
00786 dcc[i].u.xfer->length = len;
00787 s1 = nmalloc(strlen(dcc[i].u.xfer->dir) +
00788 strlen(dcc[i].u.xfer->origname) + 1);
00789 sprintf(s1, "%s%s", dcc[i].u.xfer->dir, dcc[i].u.xfer->origname);
00790
00791 if (file_readable(s1)) {
00792 dprintf(DP_HELP, "NOTICE %s :File `%s' already exists.\n", dcc[i].nick,
00793 dcc[i].u.xfer->origname);
00794 lostdcc(i);
00795 my_free(s1);
00796 } else {
00797 my_free(s1);
00798
00799 for (j = 0; j < dcc_total; j++)
00800 if (j != i) {
00801 if ((dcc[j].type->flags & (DCT_FILETRAN | DCT_FILESEND)) ==
00802 (DCT_FILETRAN | DCT_FILESEND)) {
00803 if (!strcmp(dcc[i].u.xfer->origname, dcc[j].u.xfer->origname)) {
00804 dprintf(DP_HELP, "NOTICE %s :File `%s' is already being sent.\n",
00805 dcc[i].nick, dcc[i].u.xfer->origname);
00806 lostdcc(i);
00807 return;
00808 }
00809 }
00810 }
00811
00812 s1 = nmalloc(strlen(tempdir) + strlen(dcc[i].u.xfer->filename) + 1);
00813 sprintf(s1, "%s%s", tempdir, dcc[i].u.xfer->filename);
00814 dcc[i].u.xfer->f = fopen(s1, "w");
00815 my_free(s1);
00816 if (dcc[i].u.xfer->f == NULL) {
00817 dprintf(DP_HELP,
00818 "NOTICE %s :Can't create file `%s' (temp dir error)\n",
00819 dcc[i].nick, dcc[i].u.xfer->origname);
00820 lostdcc(i);
00821 } else {
00822 dcc[i].timeval = now;
00823 dcc[i].sock = getsock(SOCK_BINARY);
00824 if (dcc[i].sock < 0 || open_telnet_dcc(dcc[i].sock, ip, prt) < 0)
00825 dcc[i].type->eof(i);
00826 }
00827 }
00828 }
00829
00830
00831
00832 static int filesys_DCC_CHAT(char *nick, char *from, char *handle,
00833 char *object, char *keyword, char *text)
00834 {
00835 char *param, *ip, *prt, buf[512], *msg = buf;
00836 int i, sock;
00837 struct userrec *u = get_user_by_handle(userlist, handle);
00838 struct flag_record fr = { FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0 };
00839
00840 if (egg_strcasecmp(object, botname))
00841 return 0;
00842 if (!egg_strncasecmp(text, "SEND ", 5)) {
00843 filesys_dcc_send(nick, from, u, text + 5);
00844 return 1;
00845 }
00846 if (egg_strncasecmp(text, "CHAT ", 5) || !u)
00847 return 0;
00848 strcpy(buf, text + 5);
00849 get_user_flagrec(u, &fr, 0);
00850 param = newsplit(&msg);
00851 if (dcc_total == max_dcc && increase_socks_max()) {
00852 putlog(LOG_MISC, "*", DCC_TOOMANYDCCS2, "CHAT(file)", param, nick, from);
00853 } else if (glob_party(fr) || (!require_p && chan_op(fr)))
00854 return 0;
00855 else if (!glob_xfer(fr)) {
00856 if (!quiet_reject)
00857 dprintf(DP_HELP, "NOTICE %s :%s\n", nick, DCC_REFUSED2);
00858 putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED, nick, from);
00859 } else if (u_pass_match(u, "-")) {
00860 if (!quiet_reject)
00861 dprintf(DP_HELP, "NOTICE %s :%s\n", nick, DCC_REFUSED3);
00862 putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED4, nick, from);
00863 } else if (!dccdir[0]) {
00864 putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED5, nick, from);
00865 } else {
00866 ip = newsplit(&msg);
00867 prt = newsplit(&msg);
00868 sock = getsock(0);
00869 if (sock < 0 || open_telnet_dcc(sock, ip, prt) < 0) {
00870 neterror(buf);
00871 if (!quiet_reject)
00872 dprintf(DP_HELP, "NOTICE %s :%s (%s)\n", nick, DCC_CONNECTFAILED1, buf);
00873 putlog(LOG_MISC, "*", "%s: CHAT(file) (%s!%s)", DCC_CONNECTFAILED2, nick,
00874 from);
00875 putlog(LOG_MISC, "*", " (%s)", buf);
00876 killsock(sock);
00877 } else if (atoi(prt) < 1024 || atoi(prt) > 65535) {
00878
00879 if (!quiet_reject)
00880 dprintf(DP_HELP, "NOTICE %s :%s (invalid port)\n", nick,
00881 DCC_CONNECTFAILED1);
00882 putlog(LOG_FILES, "*", "%s: %s!%s", DCC_REFUSED7, nick, from);
00883
00884 } else {
00885 i = new_dcc(&DCC_FILES_PASS, sizeof(struct file_info));
00886 dcc[i].addr = my_atoul(ip);
00887 dcc[i].port = atoi(prt);
00888 dcc[i].sock = sock;
00889 strcpy(dcc[i].nick, u->handle);
00890 strcpy(dcc[i].host, from);
00891 dcc[i].status = STAT_ECHO;
00892 dcc[i].timeval = now;
00893 dcc[i].u.file->chat = get_data_ptr(sizeof(struct chat_info));
00894 strcpy(dcc[i].u.file->chat->con_chan, "*");
00895 dcc[i].user = u;
00896 putlog(LOG_MISC, "*", "DCC connection: CHAT(file) (%s!%s)", nick, from);
00897 dprintf(i, "%s\n", DCC_ENTERPASS);
00898 }
00899 }
00900 return 1;
00901 }
00902
00903 static cmd_t myctcp[] = {
00904 {"DCC", "", filesys_DCC_CHAT, "files:DCC"},
00905 {NULL, NULL, NULL, NULL}
00906 };
00907
00908 static void init_server_ctcps(char *module)
00909 {
00910 p_tcl_bind_list H_ctcp;
00911
00912 if ((H_ctcp = find_bind_table("ctcp")))
00913 add_builtins(H_ctcp, myctcp);
00914 }
00915
00916 static cmd_t myload[] = {
00917 {"server", "", (IntFunc) init_server_ctcps, "filesys:server"},
00918 {NULL, NULL, NULL, NULL}
00919 };
00920
00921 static int filesys_expmem()
00922 {
00923 return 0;
00924 }
00925
00926 static void filesys_report(int idx, int details)
00927 {
00928 if (details) {
00929 int size = filesys_expmem();
00930
00931 if (dccdir[0]) {
00932 dprintf(idx, " DCC file path: %s", dccdir);
00933 if (upload_to_cd)
00934 dprintf(idx, "\n Incoming: (user's current directory)\n");
00935 else if (dccin[0])
00936 dprintf(idx, "\n Incoming: %s\n", dccin);
00937 else
00938 dprintf(idx, " (no uploads)\n");
00939
00940 if (dcc_users)
00941 dprintf(idx, " Max users: %d\n", dcc_users);
00942 if (upload_to_cd || dccin[0])
00943 dprintf(idx, " Max upload file size: %dk\n", dcc_maxsize);
00944 } else
00945 dprintf(idx, " Filesystem module loaded, but no active dcc path "
00946 "exists.\n");
00947 dprintf(idx, " Using %d byte%s of memory\n", size,
00948 (size != 1) ? "s" : "");
00949 }
00950 }
00951
00952 static char *filesys_close()
00953 {
00954 int i;
00955 p_tcl_bind_list H_ctcp;
00956
00957 putlog(LOG_MISC, "*", "Unloading filesystem; killing all filesystem "
00958 "connections.");
00959 for (i = 0; i < dcc_total; i++)
00960 if (dcc[i].type == &DCC_FILES) {
00961 dprintf(i, DCC_BOOTED1);
00962 dprintf(i, "You have been booted from the filesystem, module "
00963 "unloaded.\n");
00964 killsock(dcc[i].sock);
00965 lostdcc(i);
00966 } else if (dcc[i].type == &DCC_FILES_PASS) {
00967 killsock(dcc[i].sock);
00968 lostdcc(i);
00969 }
00970 rem_tcl_commands(mytcls);
00971 rem_tcl_strings(mystrings);
00972 rem_tcl_ints(myints);
00973 rem_builtins(H_dcc, mydcc);
00974 rem_builtins(H_load, myload);
00975 rem_builtins(H_fil, myfiles);
00976 rem_help_reference("filesys.help");
00977 if ((H_ctcp = find_bind_table("ctcp")))
00978 rem_builtins(H_ctcp, myctcp);
00979 del_bind_table(H_fil);
00980 del_entry_type(&USERENTRY_DCCDIR);
00981 del_lang_section("filesys");
00982 module_undepend(MODULE_NAME);
00983 return NULL;
00984 }
00985
00986 EXPORT_SCOPE char *filesys_start();
00987
00988 static Function filesys_table[] = {
00989
00990 (Function) filesys_start,
00991 (Function) filesys_close,
00992 (Function) filesys_expmem,
00993 (Function) filesys_report,
00994
00995 (Function) remote_filereq,
00996 (Function) add_file,
00997 (Function) incr_file_gots,
00998 (Function) is_valid,
00999
01000 (Function) & H_fil,
01001 };
01002
01003 char *filesys_start(Function *global_funcs)
01004 {
01005 global = global_funcs;
01006
01007 module_register(MODULE_NAME, filesys_table, 2, 0);
01008 if (!module_depend(MODULE_NAME, "eggdrop", 106, 0)) {
01009 module_undepend(MODULE_NAME);
01010 return "This module requires Eggdrop 1.6.0 or later.";
01011 }
01012 if (!(transfer_funcs = module_depend(MODULE_NAME, "transfer", 2, 0))) {
01013 module_undepend(MODULE_NAME);
01014 return "This module requires transfer module 2.0 or later.";
01015 }
01016 add_tcl_commands(mytcls);
01017 add_tcl_strings(mystrings);
01018 add_tcl_ints(myints);
01019 H_fil = add_bind_table("fil", 0, builtin_fil);
01020 add_builtins(H_dcc, mydcc);
01021 add_builtins(H_fil, myfiles);
01022 add_builtins(H_load, myload);
01023 add_help_reference("filesys.help");
01024 init_server_ctcps(0);
01025 my_memcpy(&USERENTRY_DCCDIR, &USERENTRY_INFO,
01026 sizeof(struct user_entry_type) - sizeof(char *));
01027
01028 USERENTRY_DCCDIR.got_share = 0;
01029 add_entry_type(&USERENTRY_DCCDIR);
01030 DCC_FILES_PASS.timeout_val = &password_timeout;
01031 add_lang_section("filesys");
01032 return NULL;
01033 }
01034
01035 static int is_valid()
01036 {
01037 return dccdir[0];
01038 }