/***************************************************************************** * * $Id$ * Purpose ...............: Add TIC file to the BBS * ***************************************************************************** * Copyright (C) 1997-2004 * * Michiel Broek FIDO: 2:280/2802 * Beekmansbos 10 * 1971 BV IJmuiden * the Netherlands * * This file is part of MBSE BBS. * * This BBS is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * MBSE BBS is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MBSE BBS; see the file COPYING. If not, write to the Free * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ #include "../config.h" #include "../lib/mbselib.h" #include "tic.h" #include "fsort.h" #include "addbbs.h" extern int tic_imp; /* * Add file to the BBS file database and place it in the download * directory. If it is replacing a file, a file with a matching name * will be deleted. If there is a limit on the number of files with * the same name pattern, the oldest files will be deleted. The * files database will be packed if necessary. All modifications are * done on temp files first. */ int Add_BBS() { struct FILERecord frec; int rc, i, Insert, Done = FALSE, Found = FALSE; char fdbname[PATH_MAX], fdbtemp[PATH_MAX]; char temp1[PATH_MAX], temp2[PATH_MAX], *fname, *lname, *p; FILE *fdb, *fdt; int Keep = 0, DidDelete = FALSE; fd_list *fdl = NULL; /* * First check for an existing record with the same filename, * if it exists, update the record and we are ready. This will * prevent for example allfiles.zip to get a new record everytime * and thus the download counters will be reset after a new update. */ sprintf(fdbname, "%s/fdb/fdb%ld.data", getenv("MBSE_ROOT"), tic.FileArea); if ((fdb = fopen(fdbname, "r+")) != NULL) { while (fread(&frec, sizeof(frec), 1, fdb) == 1) { if (strcmp(frec.Name, TIC.NewFile) == 0) { sprintf(temp1, "%s/%s", TIC.Inbound, TIC.NewFile); sprintf(temp2, "%s/%s", TIC.BBSpath, TIC.NewFile); mkdirs(temp2, 0755); if ((rc = file_cp(temp1, temp2))) { WriteError("Copy to %s failed: %s", temp2, strerror(rc)); fclose(fdb); return FALSE; } chmod(temp2, 0644); frec.TicAreaCRC = StringCRC32(TIC.TicIn.Area); frec.Size = TIC.FileSize; frec.Crc32 = TIC.Crc_Int; frec.Announced = TRUE; frec.FileDate = TIC.FileDate; frec.UploadDate = time(NULL); for (i = 0; i <= TIC.File_Id_Ct; i++) { strcpy(frec.Desc[i], TIC.File_Id[i]); if (i == 24) break; } if (strlen(TIC.TicIn.Magic)) sprintf(frec.Desc[i], "Magic Request: %s", TIC.TicIn.Magic); fseek(fdb, 0 - sizeof(frec), SEEK_CUR); fwrite(&frec, sizeof(frec), 1, fdb); fclose(fdb); tic_imp++; if ((i = file_rm(temp1))) WriteError("file_rm(%s): %s", temp1, strerror(i)); return TRUE; } } fclose(fdb); } /* * Create filedatabase record. */ memset(&frec, 0, sizeof(frec)); strncpy(frec.Name, TIC.NewFile, sizeof(frec.Name) -1); if (strlen(TIC.NewFullName)) { strncpy(frec.LName, TIC.NewFullName, sizeof(frec.LName) -1); } else { /* * No LFN, fake it with a lowercase copy of the 8.3 filename. */ strncpy(frec.LName, TIC.NewFile, sizeof(frec.LName) -1); for (i = 0; i < strlen(frec.LName); i++) frec.LName[i] = tolower(frec.LName[i]); } frec.TicAreaCRC = StringCRC32(TIC.TicIn.Area); frec.Size = TIC.FileSize; frec.Crc32 = TIC.Crc_Int; frec.Announced = TRUE; sprintf(frec.Uploader, "Filemgr"); frec.UploadDate = time(NULL); frec.FileDate = TIC.FileDate; for (i = 0; i <= TIC.File_Id_Ct; i++) { strcpy(frec.Desc[i], TIC.File_Id[i]); if (i == 24) break; } if (strlen(TIC.TicIn.Magic)) sprintf(frec.Desc[i], "Magic Request: %s", TIC.TicIn.Magic); sprintf(temp1, "%s/%s", TIC.Inbound, TIC.NewFile); sprintf(temp2, "%s/%s", TIC.BBSpath, frec.Name); mkdirs(temp2, 0755); if ((rc = file_cp(temp1, temp2))) { WriteError("Copy to %s failed: %s", temp2, strerror(rc)); return FALSE; } chmod(temp2, 0644); /* * If LFN = 8.3 name and is DOS 8.3 format, change the LFN to lowercase. */ if (strcmp(frec.Name, frec.LName) == 0) { p = frec.LName; while (*p) { if (islower(*p)) Found = TRUE; p++; } if (!Found) { /* * All uppercase, change to lowercase. */ tl(frec.LName); Syslog('f', "Converted LFN to lowercase: \"%s\"", frec.LName); } } Found = FALSE; lname = calloc(PATH_MAX, sizeof(char)); sprintf(lname, "%s/%s", TIC.BBSpath, frec.LName); if (symlink(temp2, lname)) { WriteError("$Create link %s to %s failed", temp2, lname); } free(lname); sprintf(fdbtemp, "%s/fdb/fdb%ld.temp", getenv("MBSE_ROOT"), tic.FileArea); if ((fdb = fopen(fdbname, "r+")) == NULL) { Syslog('+', "Fdb %s doesn't exist, creating", fdbname); if ((fdb = fopen(fdbname, "a+")) == NULL) { WriteError("$Can't create %s", fdbname); return FALSE; } chmod(fdbname, 0660); } /* * If there are no files in this area, we append the first * one and leave immediatly, keepnum and replace have no * use at this point. */ fseek(fdb, 0, SEEK_END); if (ftell(fdb) == 0) { fwrite(&frec, sizeof(frec), 1, fdb); fclose(fdb); file_rm(temp1); tic_imp++; return TRUE; } /* * There are already files in the area. We must now see at * which position to insert the new file, replace or * remove the old entry. */ fseek(fdb, 0, SEEK_SET); Insert = 0; do { if (fread(&file, sizeof(file), 1, fdb) != 1) Done = TRUE; if (!Done) { if (strcmp(frec.LName, file.LName) == 0) { Found = TRUE; Insert++; } else if (strcmp(frec.LName, file.LName) < 0) Found = TRUE; else Insert++; } } while ((!Found) && (!Done)); if (Found) { if ((fdt = fopen(fdbtemp, "a+")) == NULL) { WriteError("$Can't create %s", fdbtemp); fclose(fdb); return FALSE; } fseek(fdb, 0, SEEK_SET); /* * Copy entries till the insert point. */ for (i = 0; i < Insert; i++) { fread(&file, sizeof(file), 1, fdb); /* * Check if we are importing a file with the same * name, if so, don't copy the original database * record. The file is also overwritten. */ if (strcmp(file.LName, frec.LName) != 0) fwrite(&file, sizeof(file), 1, fdt); } if (area.AddAlpha) { /* * Insert the new entry */ fwrite(&frec, sizeof(frec), 1, fdt); } /* * Append the rest of the entries. */ while (fread(&file, sizeof(file), 1, fdb) == 1) { /* * Check if we find a file with the same name, * then we skip the record what was origionaly * in the database record. */ if (strcmp(file.LName, frec.LName) != 0) fwrite(&file, sizeof(file), 1, fdt); } if (!area.AddAlpha) { /* * Append the new entry */ fwrite(&frec, sizeof(frec), 1, fdt); } fclose(fdt); fclose(fdb); /* * Now make the changes for real. */ if (unlink(fdbname) == 0) { rename(fdbtemp, fdbname); } else { WriteError("$Can't unlink %s", fdbname); unlink(fdbtemp); return FALSE; } } else { /* * Append the new entry */ fseek(fdb, 0, SEEK_END); fwrite(&frec, sizeof(frec), 1, fdb); fclose(fdb); } /* * Delete file from the inbound */ if ((i = file_rm(temp1))) WriteError("file_rm(%s): %s", temp1, strerror(i)); /* * Handle the replace option. */ if ((strlen(TIC.TicIn.Replace)) && (tic.Replace)) { Syslog('f', "Must Replace: %s", TIC.TicIn.Replace); if ((fdb = fopen(fdbname, "r+")) != NULL) { while (fread(&file, sizeof(file), 1, fdb) == 1) { if (strlen(file.LName) == strlen(frec.LName)) { // FIXME: Search must be based on a reg_exp search if (strcasecmp(file.LName, frec.LName) != 0) { Found = TRUE; for (i = 0; i < strlen(frec.LName); i++) { if ((TIC.TicIn.Replace[i] != '?') && (toupper(TIC.TicIn.Replace[i]) != toupper(file.LName[i]))) Found = FALSE; } if (Found) { Syslog('+', "Replace: Deleting: %s", file.LName); file.Deleted = TRUE; fseek(fdb, - sizeof(file), SEEK_CUR); fwrite(&file, sizeof(file), 1, fdb); DidDelete = TRUE; } } } } fclose(fdb); } } /* * Handle the Keep number of files option */ if (TIC.KeepNum) { if ((fdb = fopen(fdbname, "r")) != NULL) { while (fread(&file, sizeof(file), 1, fdb) == 1) { if ((strlen(file.LName) == strlen(frec.LName)) && (!file.Deleted)) { Found = TRUE; for (i = 0; i < strlen(file.LName); i++) { if ((frec.LName[i] < '0') || (frec.LName[i] > '9')) { if (frec.LName[i] != file.LName[i]) { Found = FALSE; } } } if (Found) { Keep++; fill_fdlist(&fdl, file.LName, file.UploadDate); } } } fclose(fdb); } /* * If there are files to delete, mark them. */ if (Keep > TIC.KeepNum) { sort_fdlist(&fdl); if ((fdb = fopen(fdbname, "r+")) != NULL) { for (i = 0; i < (Keep - TIC.KeepNum); i++) { fname = pull_fdlist(&fdl); fseek(fdb, 0, SEEK_SET); while (fread(&file, sizeof(file), 1, fdb) == 1) { if (strcmp(file.LName, fname) == 0) { Syslog('+', "Keep %d files, deleting: %s", TIC.KeepNum, file.LName); file.Deleted = TRUE; fseek(fdb, - sizeof(file), SEEK_CUR); fwrite(&file, sizeof(file), 1, fdb); DidDelete = TRUE; } } } fclose(fdb); } } tidy_fdlist(&fdl); } /* * Now realy delete the marked files and clean the file * database. */ if (DidDelete) { if ((fdb = fopen(fdbname, "r")) != NULL) { if ((fdt = fopen(fdbtemp, "a+")) != NULL) { while (fread(&file, sizeof(file), 1, fdb) == 1) if (!file.Deleted) fwrite(&file, sizeof(file), 1, fdt); else { sprintf(temp2, "%s/%s", area.Path, file.LName); if (unlink(temp2) != 0) WriteError("$Can't unlink file %s", temp2); sprintf(temp2, "%s/%s", area.Path, file.Name); if (unlink(temp2) != 0) WriteError("$Can't unlink file %s", temp2); } fclose(fdb); fclose(fdt); if (unlink(fdbname) == 0) { rename(fdbtemp, fdbname); } else { WriteError("$Can't unlink %s", fdbname); unlink(fdbtemp); } } else { fclose(fdb); } DidDelete = FALSE; } } tic_imp++; return TRUE; }