Example #1
0
/* Parse the NOTES_IGNKEY xtra field. You must free the memory allocated
 * in here: the buffer 'ignores[0]' and the array 'ignores'.
 */
int get_note_ignores(struct userrec *u, char ***ignores)
{
  struct xtra_key *xk;
  char *buf, *p;
  int ignoresn;

  /* Hullo? sanity? */
  if (!u)
    return 0;
  xk = getnotesentry(u);
  if (!xk)
    return 0;

  rmspace(xk->data);
  buf = user_malloc(strlen(xk->data) + 1);
  strcpy(buf, xk->data);
  p = buf;

  /* Split up the string into small parts */
  *ignores = nmalloc(sizeof(char *) + 100);
  **ignores = p;
  ignoresn = 1;
  while ((p = strchr(p, ' ')) != NULL) {
    *ignores = nrealloc(*ignores, sizeof(char *) * (ignoresn + 1));
    (*ignores)[ignoresn] = p + 1;
    ignoresn++;
    *p = 0;
    p++;
  }
  return ignoresn;
}
Example #2
0
/* nalloc() - service allocation request */
void* numa_allocator::nalloc(unsigned ssize) {
	// get cache-line alignment for request
	int alignment = (ssize <= cache_size / 2)? cache_size / 2: cache_size;

	/* if the last allocation was half a cache line and we want a full cache line, we move
	   the free space pointer forward a half cache line so we don't spill over cache lines */
	if(last_alloc_half && (alignment == cache_size)) {
		buf_cur = (char*)buf_cur + (cache_size / 2);
		last_alloc_half = false;
	}
	else if(!last_alloc_half && (alignment == cache_size / 2)) {
		last_alloc_half = true;
	}

	// get alignment size
	unsigned aligned_size = align(ssize, alignment);

	// reallocate if not enough space left
	if((char*)buf_cur + aligned_size > (char*)buf_start + buf_size) {
		nrealloc();
	}

	// service allocation request
	buf_old = buf_cur;
	buf_cur = (char*)buf_cur + aligned_size;
	return buf_old;
}
Example #3
0
/* Increase number of filelist entries.
 */
static void filelist_add(filelist_t *flist, char *filename)
{
  flist->tot++;
  flist->elements = nrealloc(flist->elements, flist->tot * sizeof(filelist_t));
  FILELIST_LE(flist).fn = nmalloc(strlen(filename) + 1);
  strcpy(FILELIST_LE(flist).fn, filename);
  FILELIST_LE(flist).output = NULL;
}
Example #4
0
/* new botnet member */
int addparty(char *bot, char *nick, int chan, char flag, int sock,
	     char *from, int *idx)
{
  int i;

  Context;
  for (i = 0; i < parties; i++) {
    /* just changing the channel of someone already on? */
    if (!strcasecmp(party[i].bot, bot) &&
	(party[i].sock == sock)) {
      int oldchan = party[i].chan;

      party[i].chan = chan;
      party[i].timer = now;
      if (from[0]) {
	if (flag == ' ')
	  flag = '-';
	party[i].flag = flag;
	if (party[i].from)
	  nfree(party[i].from);
	party[i].from = nmalloc(strlen(from) + 1);
	strcpy(party[i].from, from);
      }
      *idx = i;
      return oldchan;
    }
  }
  /* new member */
  if (parties == maxparty) {
    maxparty += 50;
    party = (party_t *) nrealloc((void *) party, maxparty * sizeof(party_t));
  }
  strncpy(party[parties].nick, nick, HANDLEN);
  party[parties].nick[HANDLEN] = 0;
  strncpy(party[parties].bot, bot, HANDLEN);
  party[parties].bot[HANDLEN] = 0;
  party[parties].chan = chan;
  party[parties].sock = sock;
  party[parties].status = 0;
  party[parties].away = 0;
  party[parties].timer = now;	/* cope. */
  if (from[0]) {
    if (flag == ' ')
      flag = '-';
    party[parties].flag = flag;
    party[parties].from = nmalloc(strlen(from) + 1);
    strcpy(party[parties].from, from);
  } else {
    party[parties].flag = ' ';
    party[parties].from = nmalloc(10);
    strcpy(party[parties].from, "(unknown)");
  }
  *idx = parties;
  parties++;
  return -1;
}
Example #5
0
static void schan_members_rename(struct llist_header *head, char *oldnick, char *newnick)
{
	struct stats_member *m;

	m = llist_find(head, (void *)oldnick);
	if (!m)
		return;
	Assert(newnick);
	m->nick = nrealloc(m->nick, strlen(newnick) + 1);
	strcpy(m->nick, newnick);
}
Example #6
0
/* Add data to the end of filelist entry's output string
 */
static void filelist_addout(filelist_t *flist, char *desc)
{
  if (FILELIST_LE(flist).output) {
    FILELIST_LE(flist).output = nrealloc(FILELIST_LE(flist).output,
                                strlen(FILELIST_LE(flist).output) +
                                strlen(desc) + 1);
    strcat(FILELIST_LE(flist).output, desc);
  } else {
    FILELIST_LE(flist).output = nmalloc(strlen(desc) + 1);
    strcpy(FILELIST_LE(flist).output, desc);
  }
}
Example #7
0
/* This function is called to enlarge the static sockettable in a thread.
 * It keeps the mainthread dcc table enlarging with the main thread sockettable
 * If this fails because the upper limit max_socks is reached, -1 is returned.
 * If this was called from the main thread, it updates the socklist variable
 *
 * increase_socks_max() can be called by Tcl threads
 */
int increase_socks_max()
{
  struct threaddata *td = threaddata();
  int osock = td->MAXSOCKS;

  if (max_socks < 1)
    max_socks = 1;

  if (td->MAXSOCKS == max_socks) {
    putlog(LOG_MISC, "*", "Maximum socket limit reached. Consider raising max-socks.");
    return -1;
  }

  td->MAXSOCKS += 10;
  if (td->MAXSOCKS > max_socks)
    td->MAXSOCKS = max_socks;

  if (td->socklist)
    td->socklist = nrealloc(td->socklist, sizeof(sock_list) * td->MAXSOCKS);
  else
    td->socklist = nmalloc(sizeof(sock_list) * td->MAXSOCKS);
  for (; osock < td->MAXSOCKS; osock++)
    td->socklist[osock].flags = SOCK_UNUSED;

  if (td->mainthread) {
    max_dcc = td->MAXSOCKS - 10;
    if (max_dcc < 1)
      max_dcc = 1;
    if (dcc)
      dcc = nrealloc(dcc, sizeof(struct dcc_t) * max_dcc);
    else
      dcc = nmalloc(sizeof(struct dcc_t) * max_dcc);
    socklist = td->socklist;
  }

  return 0;
}
Example #8
0
static void push_str(struct lexer *lex, char *str)
{
  /* {{{ */
  ptrdiff_t offset = lex->str_gc.curr - lex->str_gc.ptr;

  /* handle overflow */
  if (offset >= (signed)lex->str_gc.size){
    /* grow the stack to be twice as big as it was */
    lex->str_gc.size <<= 1;
    lex->str_gc.ptr = nrealloc(lex->str_gc.ptr, sizeof(char *) * lex->str_gc.size);
    lex->str_gc.curr = lex->str_gc.ptr + offset;
  }

  *lex->str_gc.curr = str; /* set up the current 'cell' */
  lex->str_gc.curr++; /* move on to the next 'cell' */
  /* }}} */
}
Example #9
0
static char *HEX(va_list ap)
{
	int mem_size = MAX_STR_LEN;
	char *result = (char *)nmalloc(mem_size + 1);
	unsigned int data;
	int threshold;
	int nibble;
	int i, j;

	i = 0;
	VA_LOOP_BEGIN(ap, current)
	{
		data = (unsigned int)current->val.i;

		/* Simulate %02X specifier */
		threshold = 7;
		j = 1;
		do {
			nibble = data >> 28;

			if (nibble != 0 && threshold == 7)
				threshold = j;

			if (j >= threshold) {
				if (i >= mem_size) {
					mem_size *= 2;
					result = (char *)nrealloc(result,
							mem_size + 1);
				}
				result[i++] = hex2ascii(nibble);
			}

			data <<= 4;
			++j;
		} while (j <= 8);
	}
Example #10
0
File: prompt.c Project: ris21/yoda
/* Read in a character, interpret it as a shortcut or toggle if
 * necessary, and return it.
 * Set ran_func to TRUE if we ran a function associated with a
 * shortcut key, and set finished to TRUE if we're done after running
 * or trying to run a function associated with a shortcut key.
 * refresh_func is the function we will call to refresh the edit window. */
int do_statusbar_input(bool *ran_func, bool *finished,
	void (*refresh_func)(void))
{
    int input;
	/* The character we read in. */
    static int *kbinput = NULL;
	/* The input buffer. */
    static size_t kbinput_len = 0;
	/* The length of the input buffer. */
    const sc *s;
    bool have_shortcut = FALSE;
    const subnfunc *f;

    *ran_func = FALSE;
    *finished = FALSE;

    /* Read in a character. */
    input = get_kbinput(bottomwin);

#ifndef NANO_TINY
    if (input == KEY_WINCH)
	return KEY_WINCH;
#endif

#ifndef DISABLE_MOUSE
    /* If we got a mouse click and it was on a shortcut, read in the
     * shortcut character. */
    if (func_key && input == KEY_MOUSE) {
	if (do_statusbar_mouse() == 1)
	    input = get_kbinput(bottomwin);
	else {
	    meta_key = FALSE;
	    func_key = FALSE;
	    input = ERR;
	}
    }
#endif

    /* Check for a shortcut in the current list. */
    s = get_shortcut(&input);

    /* If we got a shortcut from the current list, or a "universal"
     * statusbar prompt shortcut, set have_shortcut to TRUE. */
    have_shortcut = (s != NULL);

    /* If we got a non-high-bit control key, a meta key sequence, or a
     * function key, and it's not a shortcut or toggle, throw it out. */
    if (!have_shortcut) {
	if (is_ascii_cntrl_char(input) || meta_key || func_key) {
	    beep();
	    meta_key = FALSE;
	    func_key = FALSE;
	    input = ERR;
	}
    }

    /* If we got a character, and it isn't a shortcut or toggle,
     * it's a normal text character.  Display the warning if we're
     * in view mode, or add the character to the input buffer if
     * we're not. */
    if (input != ERR && !have_shortcut) {
	/* If we're using restricted mode, the filename isn't blank,
	 * and we're at the "Write File" prompt, disable text input. */
	if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' ||
		currmenu != MWRITEFILE) {
	    kbinput_len++;
	    kbinput = (int *)nrealloc(kbinput, kbinput_len * sizeof(int));
	    kbinput[kbinput_len - 1] = input;
	}
     }

    /* If we got a shortcut, or if there aren't any other characters
     * waiting after the one we read in, we need to display all the
     * characters in the input buffer if it isn't empty. */
    if (have_shortcut || get_key_buffer_len() == 0) {
	if (kbinput != NULL) {
	    /* Display all the characters in the input buffer at
	     * once, filtering out control characters. */
	    char *output = charalloc(kbinput_len + 1);
	    size_t i;
	    bool got_enter;
		/* Whether we got the Enter key. */

	    for (i = 0; i < kbinput_len; i++)
		output[i] = (char)kbinput[i];
	    output[i] = '\0';

	    do_statusbar_output(output, kbinput_len, &got_enter, FALSE);

	    free(output);

	    /* Empty the input buffer. */
	    kbinput_len = 0;
	    free(kbinput);
	    kbinput = NULL;
	}

	if (have_shortcut) {
	    if (s->scfunc == do_tab || s->scfunc == do_enter_void)
		;
	    else if (s->scfunc == total_refresh)
		total_statusbar_refresh(refresh_func);
	    else if (s->scfunc == do_cut_text_void) {
		/* If we're using restricted mode, the filename
		 * isn't blank, and we're at the "Write File"
		 * prompt, disable Cut. */
		if (!ISSET(RESTRICTED) || openfile->filename[0] ==
			'\0' || currmenu != MWRITEFILE)
		    do_statusbar_cut_text();
	    } else if (s->scfunc == do_left)
		do_statusbar_left();
	    else if (s->scfunc == do_right)
		do_statusbar_right();
#ifndef NANO_TINY
	    else if (s->scfunc == do_prev_word_void)
		do_statusbar_prev_word(FALSE);
	    else if (s->scfunc == do_next_word_void)
		do_statusbar_next_word(FALSE);
#endif
	    else if (s->scfunc == do_home)
		do_statusbar_home();
	    else if (s->scfunc == do_end)
		do_statusbar_end();
	    else if (s->scfunc == do_verbatim_input) {
		/* If we're using restricted mode, the filename
		 * isn't blank, and we're at the "Write File"
		 * prompt, disable verbatim input. */
		if (!ISSET(RESTRICTED) || currmenu != MWRITEFILE ||
			openfile->filename[0] == '\0') {
		    bool got_enter;
		    /* Whether we got the Enter key. */

		    do_statusbar_verbatim_input(&got_enter);

		    /* If we got the Enter key, remove it from the input
		     * buffer, set input to the key value for Enter, and
		     * set finished to TRUE to indicate that we're done. */
		    if (got_enter) {
			get_input(NULL, 1);
			input = sc_seq_or(do_enter_void, 0);
			*finished = TRUE;
		    }
		}
	    } else if (s->scfunc == do_delete) {
		/* If we're using restricted mode, the filename
		 * isn't blank, and we're at the "Write File"
		 * prompt, disable Delete. */
		if (!ISSET(RESTRICTED) || openfile->filename[0] ==
			'\0' || currmenu != MWRITEFILE)
		    do_statusbar_delete();
	    } else if (s->scfunc == do_backspace) {
		/* If we're using restricted mode, the filename
		 * isn't blank, and we're at the "Write File"
		 * prompt, disable Backspace. */
		if (!ISSET(RESTRICTED) || openfile->filename[0] ==
			'\0' || currmenu != MWRITEFILE)
		    do_statusbar_backspace();
	    } else {
		/* Handle any other shortcut in the current menu, setting
		 * ran_func to TRUE if we try to run their associated
		 * functions and setting finished to TRUE to indicate
		 * that we're done after running or trying to run their
		 * associated functions. */
		f = sctofunc((sc *) s);
		if (s->scfunc != NULL) {
		    *ran_func = TRUE;
		    if (f && (!ISSET(VIEW_MODE) || f->viewok) &&
				f->scfunc != do_gotolinecolumn_void)
			f->scfunc();
		}
		*finished = TRUE;
	    }
	}
    }

    return input;
}
Example #11
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;
}
Example #12
0
static int do_dcc_send(int idx, char *dir, char *fn, char *nick, int resend)
{
  char *s = NULL, *s1 = NULL;
  int x;

  if (nick && strlen(nick) > NICKMAX)
    nick[NICKMAX] = 0;
  if (dccdir[0] == 0) {
    dprintf(idx, "DCC file transfers not supported.\n");
    putlog(LOG_FILES, "*", "Refused dcc %sget %s from [%s]", resend ? "re" : "",
           fn, dcc[idx].nick);
    return 0;
  }
  if (strchr(fn, '/') != NULL) {
    dprintf(idx, "Filename cannot have '/' in it...\n");
    putlog(LOG_FILES, "*", "Refused dcc %sget %s from [%s]", resend ? "re" : "",
           fn, dcc[idx].nick);
    return 0;
  }
  if (dir[0]) {
    s = nmalloc(strlen(dccdir) + strlen(dir) + strlen(fn) + 2);
    sprintf(s, "%s%s/%s", dccdir, dir, fn);
  } else {
    s = nmalloc(strlen(dccdir) + strlen(fn) + 1);
    sprintf(s, "%s%s", dccdir, fn);
  }

  if (!file_readable(s)) {
    dprintf(idx, "No such file.\n");
    putlog(LOG_FILES, "*", "Refused dcc %sget %s from [%s]", resend ? "re" :
           "", fn, dcc[idx].nick);
    my_free(s);
    return 0;
  }

  if (!nick || !nick[0])
    nick = dcc[idx].nick;
  /* Already have too many transfers active for this user?  queue it */
  if (at_limit(nick)) {
    char xxx[1024];

    sprintf(xxx, "%d*%s%s", (int) strlen(dccdir), dccdir, dir);
    queue_file(xxx, fn, dcc[idx].nick, nick);
    dprintf(idx, "Queued: %s to %s\n", fn, nick);
    my_free(s);
    return 1;
  }
  if (copy_to_tmp) {
    char *tempfn = mktempfile(fn);

    /* Copy this file to /tmp, add a random prefix to the filename. */
    s = nrealloc(s, strlen(dccdir) + strlen(dir) + strlen(fn) + 2);
    sprintf(s, "%s%s%s%s", dccdir, dir, dir[0] ? "/" : "", fn);
    s1 = nrealloc(s1, strlen(tempdir) + strlen(tempfn) + 1);
    sprintf(s1, "%s%s", tempdir, tempfn);
    my_free(tempfn);
    if (copyfile(s, s1) != 0) {
      dprintf(idx, "Can't make temporary copy of file!\n");
      putlog(LOG_FILES | LOG_MISC, "*",
             "Refused dcc %sget %s: copy to %s FAILED!",
             resend ? "re" : "", fn, tempdir);
      my_free(s);
      my_free(s1);
      return 0;
    }
  } else {
    s1 = nrealloc(s1, strlen(dccdir) + strlen(dir) + strlen(fn) + 2);
    sprintf(s1, "%s%s%s%s", dccdir, dir, dir[0] ? "/" : "", fn);
  }
  s = nrealloc(s, strlen(dir) + strlen(fn) + 2);
  sprintf(s, "%s%s%s", dir, dir[0] ? "/" : "", fn);
  x = _dcc_send(idx, s1, nick, s, resend);
  if (x != DCCSEND_OK)
    wipe_tmp_filename(s1, -1);
  my_free(s);
  my_free(s1);
  return x;
}
Example #13
0
static void report_seenreq(char *channel, char *nick)
{
  seenreq *l, *ll;
  seenreq_by *b, *bb;
  char *reply, *tmp;
  int nr;

  if (!tell_seens)
    return;
  ll = NULL;
  l = requests;
  reply = NULL;
  while (l) {
    if (!strcasecmp(l->nick, nick)) {
      reset_global_vars();
      glob_slang = slang_find(coreslangs, slang_chanlang_get(chanlangs, channel));
      glob_nick = nick;
      nr = count_seenreq(l->by);
      if (nr == 1) {
        glob_seenrequest = l;
        dprintf(DP_HELP, "NOTICE %s :%s\n", l->nick, SLONELOOK);
      } else {
        sortrequests(l);
        glob_seenrequest = l;
        glob_seenrequests = nr;
        tmp = SLMORELOOKS;
        reply = nmalloc(strlen(tmp) + 1);
	    strcpy(reply, tmp);
	    nr = 0;
        for (b = l->by; b; b = b->next) {
          nr++;
          reply = nrealloc(reply, strlen(reply) + ((nr == 1) ? 1 : 2) + strlen(b->who) + 1);
          sprintf(reply, "%s%s%s", reply, (nr == 1) ? " " : ", ", b->who);
	    }
        tmp = SLLASTLOOK;
        reply = nrealloc(reply, strlen(reply) + 2 + strlen(tmp) + 1);
        sprintf(reply, "%s. %s", reply, tmp);
	    dprintf(DP_HELP, "NOTICE %s :%s\n", l->nick, reply);
        nfree(reply);
      }
      b = l->by;
      while (b) {
        bb = b->next;
        nfree(b->who);
        nfree(b->host);
        nfree(b->chan);
        nfree(b);
        b = bb;
      }
      nfree(l->nick);
      if (ll)
        ll->next = l->next;
      else
        requests = l->next;
      nfree(l);
      if (ll)
        l = ll->next;
      else
        l = requests;
    } else {
      ll = l;
      l = l->next;
    }
  }
}
Example #14
0
/* do_seen(): Checks if someone matches the mask, and returns the reply
 * mask : first paramater (e.g. "G`Quann", "G`Quann", "*!*@*.isp.de", ...)
 * nick : nick of the one, who triggered the command
 * uhost: user@host of nick
 * chan : chan, where the command was triggered
 * bns  :
 *        1 : do a botnet-seen if no matches are found
 *        0 : don't do a botnet-seen
 *       -1 : return NULL instead of text, if no matches were found
 *            (necessary for botnet seen)
 */
static char *do_seen(char *mask, char *nick, char *uhost, char *chan, int bns)
{
  char hostbuf[UHOSTLEN + 1], *host, *newhost, *tmp, *dur;
  seendat *l;
  gseenres *r;
  int wild, nr;
  char bnquery[256];
  struct userrec *u;
  struct laston_info *li;
  struct chanset_t *ch;

  Context;
  start_seentime_calc();
  if (seen_reply) {
    nfree(seen_reply);
    seen_reply = NULL;
  }
  l = NULL;
  li = NULL;
  host = hostbuf;
  newhost = NULL;
  mask = newsplit(&mask);
  glob_query = mask;
  while (mask[0] == ' ')
    mask++;
  if (!mask[0]) {
    return SLNOPARAM;
  }
  if (strchr(mask, '?') || strchr(mask, '*')) {
    // if wildcard-searches ares not allowed, then either return
    // NULL (for botnet-seen), or a appropriate warning
    if (!wildcard_search) {
      if (bns == -1)
        return NULL;
      else
        return SLNOWILDCARDS;
    } else
      wild = 1;
  } else {
    if (strlen(mask) > seen_nick_len) // don't process if requested nick is too long
      return SLTOOLONGNICK;      // (e.g. stop stupid jokes)
    if (!strcasecmp(mask, nick)) {
      return SLMIRROR;
    }
    // check if the nick is on the current channel
    if (onchan(mask, chan))
      return SLONCHAN;
    if ((glob_othernick = handonchan(mask, chan)))
      return SLHANDONCHAN;
    // check if it is on any other channel
    if ((ch = onanychan(mask))) {
#if EGG_IS_MIN_VER(10500)
      if (!secretchan(ch->dname)) {
	glob_otherchan = ch->dname;
        return SLONOTHERCHAN;
      }
#else
      if (!secretchan(ch->name)) {
	glob_otherchan = ch->name;
        return SLONOTHERCHAN;
      }
#endif
    }
    // check if the user who uses this handle is on the channel under
    // a different nick
    if ((ch = handonanychan(mask))) {
#if EGG_IS_MIN_VER(10500)
      if (!secretchan(ch->dname)) {
        glob_otherchan = ch->dname;
        return SLONOTHERCHAN;
      }
#else
      if (!secretchan(ch->name)) {
        glob_otherchan = ch->name;
        return SLONOTHERCHAN;
      }
#endif
    }
    add_seenreq(mask, nick, uhost, chan, now);
    wild = 0;
    l = findseen(mask);
    // if there's a result, and if we don't want to search for the same user
    // under a different nick, just make a do_seennick on the result
    if (l && !fuzzy_search) {
      tmp = do_seennick(l);
      end_seentime_calc();
      return tmp;
    }
    if (!l) {
      u = get_user_by_handle(userlist, mask);
      if (u) {
        li = get_user(&USERENTRY_LASTON, u);
      }
      if (!u || !li) {
        if (bns == -1) {       // if bns is 0, then do_seen() was triggered by
          end_seentime_calc(); // a botnet seen function, which needs a clear
          return NULL;         // NULL to detect if there was a result or not
        }
        tmp = SLNOTSEEN;
        if (bns && ((strlen(mask) + strlen(nick) + strlen(uhost)
            + strlen(chan) + 20) < 255)) {
          debug0("trying botnet seen");
          if (bnsnick)
            nfree(bnsnick);
          if (bnschan)
            nfree(bnschan);
          bnsnick = nmalloc(strlen(nick) + 1);
          strcpy(bnsnick, nick);
          bnschan = nmalloc(strlen(chan) + 1);
          strcpy(bnschan, chan);
          sprintf(bnquery, "gseen_req %s %s %s %s", mask, nick, uhost, chan);
          botnet_send_zapf_broad(-1, botnetnick, NULL, bnquery);
        }
      } else {
        // we have a matching handle, no seen-entry, but a laston entry
        // in the userbase, so let's just return that one.
        dur = gseen_duration(now - li->laston);
        glob_laston = dur;
        tmp = SLPOORSEEN;
        seen_reply = nmalloc(strlen(tmp) + 1);
        strcpy(seen_reply, tmp);
        end_seentime_calc();
        return seen_reply;
      }
      end_seentime_calc();
      return tmp;
    }
    // now prepare the host for fuzzy-search
    if (strlen(l->host) < UHOSTLEN) {
      maskstricthost(l->host, host);
      host = strchr(host, '!') + 1; // strip nick from host for faster search
    } else {
      end_seentime_calc();
      return "error, too long host";
    }
  }
  if (l && (l->type == SEEN_CHPT)) {
    tmp = do_seennick(l);
    end_seentime_calc();
    return tmp;
  }
  numresults = 0;
  // wildmatch_seens uses a global var to store hosts in it
  // (to prevent massive nmalloc/nfree-usage), so don't forget
  // to initialize and free it
  temp_wildmatch_host = my_malloc(1);
  wildmatch_seens(host, mask, wild);
  my_free(temp_wildmatch_host);
  temp_wildmatch_host = NULL;
  if (!results) {
    end_seentime_calc();
    if (bns == -1)
      return NULL; // let the botnet seen function know, that seen failed
    return SLNOMATCH;
  }
  if (numresults >= max_matches) {
    end_seentime_calc();
    free_seenresults();
    return SLTOOMANYMATCHES;
  }
  sortresults();
  if (strcasecmp(results->seen->nick, mask)) {
    // if the user's latest nick is not the nick for which we were searching,
    // say that there were multiple matches and display the latest one
    if (numresults == 1)
      tmp = SLONEMATCH;
    else if (numresults <= 20)
      tmp = SLLITTLEMATCHES;
    else
      tmp = SLMANYMATCHES;
    seen_reply = nmalloc(strlen(tmp) + 1);
    strcpy(seen_reply, tmp);
    nr = 0;
    for (r = results; (r && (nr < 20)); r = r->next) {
      nr++;
      if (nr > 1) {
        seen_reply = nrealloc(seen_reply, 1 + strlen(seen_reply) + 1 + strlen(r->seen->nick) + 1);
        strcat(seen_reply, ", ");
      } else {
	seen_reply = nrealloc(seen_reply, 1 + strlen(seen_reply) + strlen(r->seen->nick) + 1);
        strcat(seen_reply, " ");
      }
      strcat(seen_reply, r->seen->nick);
    }
    tmp = do_seennick(results->seen);
    seen_reply = nrealloc(seen_reply, 2 + strlen(seen_reply) + strlen(tmp) + 1);
    sprintf(seen_reply, "%s. %s", seen_reply, tmp);
  } else { // first result is the nick which we were searching for
    // just return the info for this nick and don't care about other results
    tmp = do_seennick(results->seen);
    seen_reply = nmalloc(strlen(tmp) + 1);
    strcpy(seen_reply, tmp);
  }
  free_seenresults();
  end_seentime_calc();
  return seen_reply;
}