Exemple #1
0
/* Add command (remove old one if necessary)
 */
static int bind_bind_entry(tcl_bind_list_t *tl, const char *flags,
                           const char *cmd, const char *proc)
{
  tcl_cmd_t *tc;
  tcl_bind_mask_t *tm;

  /* Search for matching bind in bind list. */
  for (tm = tl->first; tm; tm = tm->next) {
    if (tm->flags & TBM_DELETED)
      continue;
    if (!strcmp(cmd, tm->mask))
      break;                    /* Found it! fall out! */
  }

  /* Create bind if it doesn't exist yet. */
  if (!tm) {
    tm = nmalloc_null(sizeof *tm);
    tm->mask = nmalloc(strlen(cmd) + 1);
    strcpy(tm->mask, cmd);

    /* Link into linked list of binds. */
    tm->next = tl->first;
    tl->first = tm;
  }

  /* Proc already defined? If so, replace. */
  for (tc = tm->first; tc; tc = tc->next) {
    if (tc->attributes & TC_DELETED)
      continue;
    if (!egg_strcasecmp(tc->func_name, proc)) {
      tc->flags.match = FR_GLOBAL | FR_CHAN;
      break_down_flags(flags, &(tc->flags), NULL);
      return 1;
    }
  }

  /* If this bind list is not stackable, remove the
   * old entry from this bind. */
  if (!(tl->flags & HT_STACKABLE)) {
    for (tc = tm->first; tc; tc = tc->next) {
      if (tc->attributes & TC_DELETED)
        continue;
      /* NOTE: We assume there's only one not-yet-deleted entry. */
      tc->attributes |= TC_DELETED;
      break;
    }
  }

  tc = nmalloc_null(sizeof *tc);
  tc->flags.match = FR_GLOBAL | FR_CHAN;
  break_down_flags(flags, &(tc->flags), NULL);
  tc->func_name = nmalloc(strlen(proc) + 1);
  strcpy(tc->func_name, proc);

  /* Link into linked list of the bind's command list. */
  tc->next = tm->first;
  tm->first = tc;

  return 1;
}
Exemple #2
0
static int tcl_setflags(ClientData cd, Tcl_Interp *irp,
                        int argc, char *argv[])
{
  FILE *fdb;
  filedb_entry *fdbe;
  char *s = NULL, *p, *d;

  BADARGS(3, 4, " dir ?flags ?channel??");

  malloc_strcpy(s, argv[1]);
  if (s[strlen(s) - 1] == '/')
    s[strlen(s) - 1] = 0;
  p = strrchr(s, '/');
  if (p == NULL) {
    p = s;
    d = "";
  } else {
    *p = 0;
    p++;
    d = s;
  }

  fdb = filedb_open(d, 0);
  if (!fdb) {
    Tcl_AppendResult(irp, "-3", NULL);  /* filedb access failed */
    my_free(s);
    return TCL_OK;
  }
  filedb_readtop(fdb, NULL);
  fdbe = filedb_matchfile(fdb, ftell(fdb), p);
  my_free(s);

  if (!fdbe) {
    Tcl_AppendResult(irp, "-1", NULL);  /* No such dir */
    return TCL_OK;
  }
  if (!(fdbe->stat & FILE_DIR)) {
    Tcl_AppendResult(irp, "-2", NULL);  /* Not a dir */
    return TCL_OK;
  }
  if (argc >= 3) {
    struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
    char f[100];

    break_down_flags(argv[2], &fr, NULL);
    build_flags(f, &fr, NULL);
    malloc_strcpy(fdbe->flags_req, f);
  } else
    my_free(fdbe->flags_req);
  if (argc == 4)
    malloc_strcpy(fdbe->chan, argv[3]);

  filedb_updatefile(fdb, fdbe->pos, fdbe, UPDATE_ALL);
  free_fdbe(&fdbe);
  filedb_close(fdb);
  Tcl_AppendResult(irp, "0", NULL);
  return TCL_OK;
}
Exemple #3
0
static int botfl_unpack(struct userrec *u, struct user_entry *e)
{
  struct flag_record fr = { FR_BOT, 0, 0, 0, 0, 0 };

  break_down_flags(e->u.list->extra, &fr, NULL);
  list_type_kill(e->u.list);
  e->u.ulong = fr.bot;
  return 1;
}
Exemple #4
0
static int botfl_tcl_set(Tcl_Interp * irp, struct userrec *u,
			 struct user_entry *e, int argc, char **argv)
{
  struct flag_record fr = {FR_BOT, 0, 0, 0, 0, 0};

  BADARGS(4, 4, " handle BOTFL flags");
  if (u->flags & USER_BOT) {
    /* silently ignore for users */
    break_down_flags(argv[3], &fr, NULL);
    botfl_set(u, e, (void *) fr.bot);
  }
  return TCL_OK;
}
Exemple #5
0
/* Outputs a sorted list of files/directories matching the mask,
 * to idx.
 */
static void filedb_ls(FILE *fdb, int idx, char *mask, int showall)
{
    int ok = 0, cnt = 0, is = 0;
    char s1[81], *p = NULL;
    struct flag_record user = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
    filedb_entry *fdbe = NULL;
    filelist_t *flist = NULL;

    flist = filelist_new();
    filedb_readtop(fdb, NULL);
    fdbe = filedb_getfile(fdb, ftell(fdb), GET_FULL);
    while (fdbe) {
        ok = 1;
        if (fdbe->stat & FILE_UNUSED)
            ok = 0;
        if (ok && (fdbe->stat & FILE_DIR) && fdbe->flags_req) {
            /* Check permissions */
            struct flag_record req = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };

            break_down_flags(fdbe->flags_req, &req, NULL);
            get_user_flagrec(dcc[idx].user, &user, dcc[idx].u.file->chat->con_chan);
            if (!flagrec_ok(&req, &user)) {
                ok = 0;
            }
        }
        if (ok)
            is = 1;
        if (ok && !wild_match_file(mask, fdbe->filename))
            ok = 0;
        if (ok && (fdbe->stat & FILE_HIDDEN) && !(showall))
            ok = 0;
        if (ok) {
            /* Display it! */
            if (cnt == 0) {
                dprintf(idx, FILES_LSHEAD1);
                dprintf(idx, FILES_LSHEAD2);
            }
            filelist_add(flist, fdbe->filename);
            if (fdbe->stat & FILE_DIR) {
                char *s2 = NULL, *s3 = NULL;

                /* Too long? */
                if (strlen(fdbe->filename) > 45) {
                    /* Display the filename on its own line. */
                    s2 = nmalloc(strlen(fdbe->filename) + 3);
                    sprintf(s2, "%s/\n", fdbe->filename);
                    filelist_addout(flist, s2);
                    my_free(s2);
                } else {
                    s2 = nmalloc(strlen(fdbe->filename) + 2);
                    sprintf(s2, "%s/", fdbe->filename);
                }
                /* Note: You have to keep the sprintf and the nmalloc statements
                 *       in sync, i.e. always check that you allocate enough
                 *       memory.
                 */
                if ((fdbe->flags_req) && (user.global &(USER_MASTER | USER_JANITOR))) {
                    s3 = nmalloc(42 + strlen(s2 ? s2 : "") + 6 +
                                 strlen(FILES_REQUIRES) + strlen(fdbe->flags_req) + 1 +
                                 strlen(fdbe->chan ? fdbe->chan : "") + 1);
                    sprintf(s3, "%-30s <DIR%s>  (%s %s%s%s)\n", s2,
                            fdbe->stat & FILE_SHARE ?
                            " SHARE" : "", FILES_REQUIRES, fdbe->flags_req,
                            fdbe->chan ? " " : "", fdbe->chan ? fdbe->chan : "");
                } else {
                    s3 = nmalloc(38 + strlen(s2 ? s2 : ""));
                    sprintf(s3, "%-30s <DIR>\n", s2 ? s2 : "");
                }
                if (s2)
                    my_free(s2);
                filelist_addout(flist, s3);
                my_free(s3);
            } else {
                char s2[41], t[50], *s3 = NULL, *s4;

                s2[0] = 0;
                if (showall) {
                    if (fdbe->stat & FILE_SHARE)
                        strcat(s2, " (shr)");
                    if (fdbe->stat & FILE_HIDDEN)
                        strcat(s2, " (hid)");
                }
                egg_strftime(t, 10, "%d%b%Y", localtime(&fdbe->uploaded));
                if (fdbe->size < 1024)
                    sprintf(s1, "%5d", fdbe->size);
                else
                    sprintf(s1, "%4dk", (int) (fdbe->size / 1024));
                if (fdbe->sharelink)
                    strcpy(s1, "     ");
                /* Too long? */
                if (strlen(fdbe->filename) > 30) {
                    s3 = nmalloc(strlen(fdbe->filename) + 2);
                    sprintf(s3, "%s\n", fdbe->filename);
                    filelist_addout(flist, s3);
                    my_free(s3);
                    /* Causes filename to be displayed on its own line */
                } else
                    malloc_strcpy(s3, fdbe->filename);
                s4 = nmalloc(69 + strlen(s3 ? s3 : "") + strlen(s1) +
                             strlen(fdbe->uploader) + strlen(t) + strlen(s2));
                sprintf(s4, "%-30s %s  %-9s (%s)  %6d%s\n", s3 ? s3 : "", s1,
                        fdbe->uploader, t, fdbe->gots, s2);
                if (s3)
                    my_free(s3);
                filelist_addout(flist, s4);
                my_free(s4);
                if (fdbe->sharelink) {
                    s4 = nmalloc(9 + strlen(fdbe->sharelink));
                    sprintf(s4, "   --> %s\n", fdbe->sharelink);
                    filelist_addout(flist, s4);
                    my_free(s4);
                }
            }
            if (fdbe->desc) {
                p = strchr(fdbe->desc, '\n');
                while (p != NULL) {
                    *p = 0;
                    if ((fdbe->desc)[0]) {
                        char *sd;

                        sd = nmalloc(strlen(fdbe->desc) + 5);
                        sprintf(sd, "   %s\n", fdbe->desc);
                        filelist_addout(flist, sd);
                        my_free(sd);
                    }
                    strcpy(fdbe->desc, p + 1);
                    p = strchr(fdbe->desc, '\n');
                }
                if ((fdbe->desc)[0]) {
                    char *sd;

                    sd = nmalloc(strlen(fdbe->desc) + 5);
                    sprintf(sd, "   %s\n", fdbe->desc);
                    filelist_addout(flist, sd);
                    my_free(sd);
                }
            }
            cnt++;
        }
        free_fdbe(&fdbe);
        fdbe = filedb_getfile(fdb, ftell(fdb), GET_FULL);
    }
    if (is == 0)
        dprintf(idx, FILES_NOFILES);
    else if (cnt == 0)
        dprintf(idx, FILES_NOMATCH);
    else {
        filelist_sort(flist);
        filelist_idxshow(flist, idx);
        dprintf(idx, "--- %d file%s.\n", cnt, cnt != 1 ? "s" : "");
    }
    filelist_free(flist);
}
Exemple #6
0
static void filedb_ls(FILE *f, int idx, char *mask, int showall)
{
  filedb fdb;
  int ok = 0, cnt = 0, is = 0;
  char s[81], s1[81], *p;
  struct flag_record user = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};

  rewind(f);
  while (!feof(f)) {
    fread(&fdb, sizeof(filedb), 1, f);
    if (!feof(f)) {
      ok = 1;
      if (fdb.stat & FILE_UNUSED)
	ok = 0;
      if (fdb.stat & FILE_DIR) {
	/* check permissions */
	struct flag_record req = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};

	break_down_flags(fdb.flags_req, &req, NULL);
	get_user_flagrec(dcc[idx].user, &user,
			 dcc[idx].u.file->chat->con_chan);
	if (!flagrec_ok(&req, &user))
	  ok = 0;
      }
      if (ok)
	is = 1;
      if (!wild_match_file(mask, fdb.filename))
	ok = 0;
      if ((fdb.stat & FILE_HIDDEN) && !(showall))
	ok = 0;
      if (ok) {
	/* display it! */
	if (cnt == 0) {
	  dprintf(idx, FILES_LSHEAD1);
	  dprintf(idx, FILES_LSHEAD2);
	}
	if (fdb.stat & FILE_DIR) {
	  char s2[50];

	  /* too long? */
	  if (strlen(fdb.filename) > 45) {
	    dprintf(idx, "%s/\n", fdb.filename);
	    s2[0] = 0;
	    /* causes filename to be displayed on its own line */
	  } else
	    sprintf(s2, "%s/", fdb.filename);
	  if ((fdb.flags_req[0]) &&
	      (user.global &(USER_MASTER | USER_JANITOR))) {
	    dprintf(idx, "%-30s <DIR%s>  (%s %s%s%s)\n", s2,
		    fdb.stat & FILE_SHARE ?
		    " SHARE" : "", FILES_REQUIRES, fdb.flags_req,
		    fdb.chname[0] ? " " : "", fdb.chname);
	  } else
	    dprintf(idx, "%-30s <DIR>\n", s2);
	} else {
	  char s2[41];

	  s2[0] = 0;
	  if (showall) {
	    if (fdb.stat & FILE_SHARE)
	      strcat(s2, " (shr)");
	    if (fdb.stat & FILE_HIDDEN)
	      strcat(s2, " (hid)");
	  }
	  strcpy(s, ctime(&fdb.uploaded));
	  s[10] = 0;
	  s[7] = 0;
	  s[24] = 0;
	  strcpy(s, &s[8]);
	  strcpy(&s[2], &s[4]);
	  strcpy(&s[5], &s[22]);
	  if (fdb.size < 1024)
	    sprintf(s1, "%5d", fdb.size);
	  else
	    sprintf(s1, "%4dk", (int) (fdb.size / 1024));
	  if (fdb.sharelink[0])
	    strcpy(s1, "     ");
	  /* too long? */
	  if (strlen(fdb.filename) > 30) {
	    dprintf(idx, "%s\n", fdb.filename);
	    fdb.filename[0] = 0;
	    /* causes filename to be displayed on its own line */
	  }
	  dprintf(idx, "%-30s %s  %-9s (%s)  %6d%s\n", fdb.filename, s1,
		  fdb.uploader, s, fdb.gots, s2);
	  if (fdb.sharelink[0]) {
	    dprintf(idx, "   --> %s\n", fdb.sharelink);
	  }
	}
	if (fdb.desc[0]) {
	  p = strchr(fdb.desc, '\n');
	  while (p != NULL) {
	    *p = 0;
	    if (fdb.desc[0])
	      dprintf(idx, "   %s\n", fdb.desc);
	    strcpy(fdb.desc, p + 1);
	    p = strchr(fdb.desc, '\n');
	  }
	  if (fdb.desc[0])
	    dprintf(idx, "   %s\n", fdb.desc);
	}
	cnt++;
      }
    }
  }
  if (is == 0)
    dprintf(idx, FILES_NOFILES);
  else if (cnt == 0)
    dprintf(idx, FILES_NOMATCH);
  else
    dprintf(idx, "--- %d file%s.\n", cnt, cnt > 1 ? "s" : "");
}
Exemple #7
0
/* return 1 if i find a '.files' and convert it */
static int convert_old_db(char *path, char *newfiledb)
{
  FILE *f, *g;
  char s[256], *fn, *nick, *tm, *s1 = s;

  filedb fdb;
  int in_file = 0, i;
  long where;
  struct stat st;

  sprintf(s, "%s/.files", path);
  f = fopen(s, "r");
  if (f == NULL)
    return 0;
  g = fopen(newfiledb, "w+b");
  if (g == NULL) {
    putlog(LOG_MISC, "(!) Can't create filedb in %s", newfiledb);
    fclose(f);
    return 0;
  }
  putlog(LOG_FILES, "*", FILES_CONVERT, path);
  where = ftell(g);
  /* scan contents of .files and painstakingly create .filedb entries */
  while (!feof(f)) {
    fgets(s, 120, f);
    if (s[strlen(s) - 1] == '\n')
      s[strlen(s) - 1] = 0;
    if (!feof(f)) {
      fn = newsplit(&s1);
      rmspace(fn);
      if ((fn[0]) && (fn[0] != ';') && (fn[0] != '#')) {
	/* not comment */
	if (fn[0] == '-') {
	  /* adjust comment for current file */
	  if (in_file) {
	    rmspace(s);
	    if (strlen(s) + strlen(fdb.desc) <= 600) {
	      strcat(fdb.desc, "\n");
	      strcat(fdb.desc, s);
	      fseek(g, where, SEEK_SET);
	      fwrite(&fdb, sizeof(filedb), 1, g);
	    }
	  }
	} else {
	  in_file = 1;
	  where = ftell(g);
	  nick = newsplit(&s1);
	  rmspace(nick);
	  tm = newsplit(&s1);
	  rmspace(tm);
	  rmspace(s1);
	  i = strlen(fn) - 1;
	  if (fn[i] == '/')
	    fn[i] = 0;
	  fdb.version = FILEVERSION;
	  fdb.stat = 0;
	  fdb.desc[0] = 0;
	  fdb.chname[0] = 0;
	  fdb.flags_req[0] = 0;
	  strcpy(fdb.filename, fn);
	  strcpy(fdb.uploader, nick);
	  fdb.gots = atoi(s1);
	  fdb.sharelink[0] = 0;
	  fdb.uploaded = atoi(tm);
	  sprintf(s, "%s/%s", path, fn);
	  if (stat(s, &st) == 0) {
	    /* file is okay */
	    if (S_ISDIR(st.st_mode)) {
	      fdb.stat |= FILE_DIR;
	      if (nick[0] == '+') {
		char x[100];

		/* only do global flags, it's an old one */
		struct flag_record fr =
		{FR_GLOBAL, 0, 0, 0, 0, 0};

		break_down_flags(nick + 1, &fr, NULL);
		build_flags(x, &fr, NULL);
		/* we only want valid flags */
		strncpy(fdb.flags_req, x, 21);
		fdb.flags_req[21] = 0;
	      }
	    }
	    fdb.size = st.st_size;
	    fwrite(&fdb, sizeof(filedb), 1, g);
	  } else
	    in_file = 0;	/* skip */
	}
      }
    }
  }
  fseek(g, 0, SEEK_END);
  fclose(g);
  fclose(f);
  return 1;
}
Exemple #8
0
void showhelp(int idx, struct flag_record *flags, const char *string)
{
  struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0 };
  size_t help_siz = strlen(string) + 1000 + 1;
  char *helpstr = (char *) my_calloc(1, help_siz);
  char tmp[2] = "", flagstr[10] = "";
  bool ok = 1;

  while (string && string[0]) {
    if (*string == '%') {
      if (!strncmp(string + 1, "{+", 2)) {
        while (*string && *string != '+') {
          string++;
        }
        flagstr[0] = 0;
        while (*string && *string != '}') {
          simple_snprintf(tmp, sizeof(tmp), "%c", *string);
          strlcat(flagstr, tmp, sizeof(flagstr));
          string++;
        }
        string++;
        break_down_flags(flagstr, &fr, NULL);
        if (flagrec_ok(&fr, flags)) {
          ok = 1;
          while (*string && *string != '%') {
            simple_snprintf(tmp, sizeof(tmp), "%c", *string);
            strlcat(helpstr, tmp, help_siz);
            string++;
          }
          if (!strncmp(string + 1, "{-", 2)) {
            ok = 1;
            while (*string && *string != '}') {
              string++;
            }
            string++;
          }
        } else {
          ok = 0;
        }
      } else if (!strncmp(string + 1, "{-", 2)) {
        ok = 1;
        while (*string && *string != '}') {
          string++;
        }
        string++;
      } else if (*string == '{') {
        while (*string && *string != '}') {
          string++;
        }
      } else if (*(string + 1) == 'd') {
        string += 2;
        if (dcc[idx].u.chat->channel >= 0)
          strlcat(helpstr, settings.dcc_prefix, help_siz);
      } else if (*(string + 1) == '%') {
        string += 2;
        strlcat(helpstr, "%", help_siz);
      } else {
        if (ok) {
          simple_snprintf(tmp, sizeof(tmp), "%c", *string);
          strlcat(helpstr, tmp, help_siz);
        }
        string++;
      }
    } else {
      if (ok) {
        simple_snprintf(tmp, sizeof(tmp), "%c", *string);
        strlcat(helpstr, tmp, help_siz);
      }
      string++;
    }
  }
  helpstr[strlen(helpstr)] = 0;
  if (helpstr[0]) dumplots(idx, "", helpstr);
  free(helpstr);
}
Exemple #9
0
/* Convert '.files' db to newest db. Returns 1 if a valid file is
 * found and could be converted, 0 in all other cases.
 *
 * '.files' is a text file which contains file records built up in the
 * following way:
 *      '<filename> <nick> <tm> <gots>\n'
 *      '- <comment>\n'
 *      '- <comment>\n'
 *      ...
 */
static int convert_old_files(char *path, char *newfiledb)
{
    FILE *f, *fdb;
    char *s, *fn, *nick, *tm, *s1;
    filedb_entry *fdbe = NULL;
    int in_file = 0, i;
    struct stat st;

    s = nmalloc(strlen(path) + 8);
    sprintf(s, "%s/.files", path);
    f = fopen(s, "r");
    my_free(s);
    if (f == NULL)
        return 0;

    fdb = fopen(newfiledb, "w+b");
    if (!fdb) {
        putlog(LOG_MISC, "(!) Can't create filedb in %s", newfiledb);
        fclose(f);
        return 0;
    }
    lockfile(fdb);
    lockfile(f);
    filedb_initdb(fdb);

    putlog(LOG_FILES, "*", FILES_CONVERT, path);
    /* Scan contents of .files and painstakingly create .filedb entries */
    while (!feof(f)) {
        s = nmalloc(121);
        s1 = s;
        fgets(s, 120, f);
        if (s[strlen(s) - 1] == '\n')
            s[strlen(s) - 1] = 0;
        if (!feof(f)) {
            fn = newsplit(&s1);
            rmspace(fn);
            if ((fn[0]) && (fn[0] != ';') && (fn[0] != '#')) {
                /* Not comment */
                if (fn[0] == '-') {
                    /* Adjust comment for current file */
                    if (in_file && fdbe) {
                        rmspace(s);
                        if (fdbe->desc) {
                            fdbe->desc = nrealloc(fdbe->desc,
                                                  strlen(fdbe->desc) + strlen(s) + 2);
                            strcat(fdbe->desc, "\n");
                        } else
                            fdbe->desc = nmalloc(strlen(s) + 2);
                        strcat(fdbe->desc, s);
                    }
                } else {
                    if (fdbe) {
                        /* File pending. Write to DB */
                        filedb_addfile(fdb, fdbe);
                        free_fdbe(&fdbe);
                    }
                    fdbe = malloc_fdbe();
                    in_file = 1;
                    nick = newsplit(&s1);
                    rmspace(nick);
                    tm = newsplit(&s1);
                    rmspace(tm);
                    rmspace(s1);
                    i = strlen(fn) - 1;
                    if (fn[i] == '/')
                        fn[i] = 0;
                    malloc_strcpy(fdbe->filename, fn);
                    malloc_strcpy(fdbe->uploader, nick);
                    fdbe->gots = atoi(s1);
                    fdbe->uploaded = atoi(tm);
                    sprintf(s, "%s/%s", path, fn);
                    if (stat(s, &st) == 0) {
                        /* File is okay */
                        if (S_ISDIR(st.st_mode)) {
                            fdbe->stat |= FILE_DIR;
                            if (nick[0] == '+') {
                                char x[100];

                                /* Only do global flags, it's an old one */
                                struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };

                                break_down_flags(nick + 1, &fr, NULL);
                                build_flags(x, &fr, NULL);
                                /* We only want valid flags */
                                malloc_strcpy_nocheck(fdbe->flags_req, x);
                            }
                        }
                        fdbe->size = st.st_size;
                    } else
                        in_file = 0;        /* skip */
                }
            }
        }
        my_free(s);
    }
    if (fdbe) {
        /* File pending. Write to DB */
        filedb_addfile(fdb, fdbe);
        free_fdbe(&fdbe);
    }
    fseek(fdb, 0L, SEEK_END);
    unlockfile(f);
    unlockfile(fdb);
    fclose(fdb);
    fclose(f);
    return 1;
}
Exemple #10
0
static int tcl_mkdir(ClientData cd, Tcl_Interp *irp,
                     int argc, char *argv[])
{
  FILE *fdb;
  filedb_entry *fdbe;
  char *s = NULL, *t, *d, *p;
  struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };

  BADARGS(2, 4, " dir ?required-flags ?channel??");

  malloc_strcpy(s, argv[1]);

  if (s[strlen(s) - 1] == '/')
    s[strlen(s) - 1] = 0;

  p = strrchr(s, '/');
  if (p == NULL) {
    p = s;
    d = "";
  } else {
    *p = 0;
    p++;
    d = s;
  }

  fdb = filedb_open(d, 0);
  if (!fdb) {
    Tcl_AppendResult(irp, "-3", NULL);  /* filedb access failed */
    my_free(s);
    return TCL_OK;
  }
  filedb_readtop(fdb, NULL);
  fdbe = filedb_matchfile(fdb, ftell(fdb), p);

  if (!fdbe) {
    t = nmalloc(strlen(dccdir) + strlen(d) + strlen(p) + 2);
    sprintf(t, "%s%s/%s", dccdir, d, p);
    if (mkdir(t, 0755) != 0) {
      Tcl_AppendResult(irp, "1", NULL);
      my_free(t);
      my_free(s);
      filedb_close(fdb);
      return TCL_OK;
    }
    fdbe = malloc_fdbe();
    fdbe->stat = FILE_DIR;
    malloc_strcpy(fdbe->filename, argv[1]);
    fdbe->uploaded = now;
  } else if (!(fdbe->stat & FILE_DIR)) {
    Tcl_AppendResult(irp, "2", NULL);
    free_fdbe(&fdbe);
    my_free(s);
    filedb_close(fdb);
    return TCL_OK;
  }
  if (argc >= 3) {
    char f[100];

    break_down_flags(argv[2], &fr, NULL);
    build_flags(f, &fr, NULL);
    malloc_strcpy(fdbe->flags_req, f);
  } else if (fdbe->flags_req) {
    my_free(fdbe->flags_req);
  }
  if (argc == 4) {
    malloc_strcpy(fdbe->chan, argv[3]);
  } else if (fdbe->chan)
    my_free(fdbe->chan);

  if (!fdbe->pos)
    fdbe->pos = POS_NEW;
  filedb_updatefile(fdb, fdbe->pos, fdbe, UPDATE_ALL);
  filedb_close(fdb);
  free_fdbe(&fdbe);

  Tcl_AppendResult(irp, "0", NULL);
  return TCL_OK;
}