/* * Do completion on a list of objects. * c is SPACE, TAB, or CR * return TRUE if matched (or partially matched) * FALSE is result is ambiguous, * ABORT on error. */ static int complt(int flags, int c, char *buf, size_t nbuf, int cpos, int *nx) { struct list *lh, *lh2; struct list *wholelist = NULL; int i, nxtra, nhits, bxtra, msglen, nshown; int wflag = FALSE; char *msg; lh = lh2 = NULL; if ((flags & EFFUNC) != 0) { buf[cpos] = '\0'; wholelist = lh = complete_function_list(buf); } else if ((flags & EFBUF) != 0) { lh = &(bheadp->b_list); } else if ((flags & EFFILE) != 0) { buf[cpos] = '\0'; wholelist = lh = make_file_list(buf); } else panic("broken complt call: flags"); if (c == ' ') wflag = TRUE; else if (c != '\t' && c != CCHR('M')) panic("broken complt call: c"); nhits = 0; nxtra = HUGE; for (; lh != NULL; lh = lh->l_next) { if (memcmp(buf, lh->l_name, cpos) != 0) continue; if (nhits == 0) lh2 = lh; ++nhits; if (lh->l_name[cpos] == '\0') nxtra = -1; /* exact match */ else { bxtra = getxtra(lh, lh2, cpos, wflag); if (bxtra < nxtra) nxtra = bxtra; lh2 = lh; } } if (nhits == 0) msg = " [No match]"; else if (nhits > 1 && nxtra == 0) msg = " [Ambiguous. Ctrl-G to cancel]"; else { /* * Being lazy - ought to check length, but all things * autocompleted have known types/lengths. */ if (nxtra < 0 && nhits > 1 && c == ' ') nxtra = 1; /* ??? */ for (i = 0; i < nxtra && cpos < nbuf; ++i) { buf[cpos] = lh2->l_name[cpos]; eputc(buf[cpos++]); } /* XXX should grow nbuf */ ttflush(); free_file_list(wholelist); *nx = nxtra; if (nxtra < 0 && c != CCHR('M')) /* exact */ *nx = 0; return (TRUE); } /* * wholelist is NULL if we are doing buffers. Want to free lists * that were created for us, but not the buffer list! */ free_file_list(wholelist); /* Set up backspaces, etc., being mindful of echo line limit. */ msglen = strlen(msg); nshown = (ttcol + msglen + 2 > ncol) ? ncol - ttcol - 2 : msglen; eputs(msg); ttcol -= (i = nshown); /* update ttcol! */ while (i--) /* move back before msg */ ttputc('\b'); ttflush(); /* display to user */ i = nshown; while (i--) /* blank out on next flush */ eputc(' '); ttcol -= (i = nshown); /* update ttcol on BS's */ while (i--) ttputc('\b'); /* update ttcol again! */ *nx = nxtra; return ((nhits > 0) ? TRUE : FALSE); }
static void do_seen(int idx, char *prefix, char *nick, char *hand, char *channel, char *text) { char stuff[512], word1[512], word2[512], whotarget[512], object[512], whoredirect[512], *oix, *lastonplace = 0; struct userrec *urec; struct chanset_t *chan; struct laston_info *li; struct chanuserrec *cr; memberlist *m = NULL; int onchan = 0, i; long tv; time_t laston = 0, work; whotarget[0] = 0; whoredirect[0] = 0; object[0] = 0; /* Was ANYONE specified */ if (!text[0]) { dprintf(idx, "%sUm, %s, it might help if you ask me about _someone_...\n", prefix, nick); return; } wordshift(word1, text); oix = strchr(word1, '\''); /* Have we got a NICK's target? */ if (oix == word1) return; /* Skip anything starting with ' */ if (oix && *oix && ((oix[1] && (oix[1] == 's' || oix[1] == 'S') && !oix[2]) || (!oix[1] && (oix[-1] == 's' || oix[-1] == 'z' || oix[-1] == 'x' || oix[-1] == 'S' || oix[-1] == 'Z' || oix[-1] == 'X')))) { strncpy(object, word1, oix - word1); object[oix - word1] = 0; wordshift(word1, text); if (!word1[0]) { dprintf(idx, "%s%s's what, %s?\n", prefix, object, nick); return; } urec = get_user_by_handle(userlist, object); if (!urec) { chan = chanset; while (chan) { onchan = 0; m = ismember(chan, object); if (m) { onchan = 1; sprintf(stuff, "%s!%s", object, m->userhost); urec = get_user_by_host(stuff); if (!urec || !egg_strcasecmp(object, urec->handle)) break; strcat(whoredirect, object); strcat(whoredirect, " is "); strcat(whoredirect, urec->handle); strcat(whoredirect, ", and "); strcpy(object, urec->handle); break; } chan = chan->next; } if (!onchan) { dprintf(idx, "%sI don't think I know who %s is, %s.\n", prefix, object, nick); return; } } if (!egg_strcasecmp(word1, "bf") || !egg_strcasecmp(word1, "boyfriend")) { strcpy(whotarget, getxtra(object, "BF")); if (whotarget[0]) { sprintf(whoredirect, "%s boyfriend is %s, and ", fixnick(object), whotarget); goto targetcont; } dprintf(idx, "%sI don't know who %s boyfriend is, %s.\n", prefix, fixnick(object), nick); return; } if (!egg_strcasecmp(word1, "gf") || !egg_strcasecmp(word1, "girlfriend")) { strcpy(whotarget, getxtra(object, "GF")); if (whotarget[0]) { sprintf(whoredirect, "%s girlfriend is %s, and ", fixnick(object), whotarget); goto targetcont; } dprintf(idx, "%sI don't know who %s girlfriend is, %s.\n", prefix, fixnick(object), nick); return; } dprintf(idx, "%sWhy are you bothering me with questions about %s %s, %s?\n", prefix, fixnick(object), word1, nick); return; } /* Keyword "my" */ if (!egg_strcasecmp(word1, "my")) { wordshift(word1, text); if (!word1[0]) { dprintf(idx, "%sYour what, %s?\n", prefix, nick); return; } /* Do I even KNOW the requestor? */ if (hand[0] == '*' || !hand[0]) { dprintf(idx, "%sI don't know you, %s, so I don't know about your %s.\n", prefix, nick, word1); return; } /* "my boyfriend" */ if (!egg_strcasecmp(word1, "boyfriend") || !egg_strcasecmp(word1, "bf")) { strcpy(whotarget, getxtra(hand, "BF")); if (whotarget[0]) { sprintf(whoredirect, "%s, your boyfriend is %s, and ", nick, whotarget); } else { dprintf(idx, "%sI didn't know you had a boyfriend, %s\n", prefix, nick); return; } } /* "my girlfriend" */ else if (!egg_strcasecmp(word1, "girlfriend") || !egg_strcasecmp(word1, "gf")) { strcpy(whotarget, getxtra(hand, "GF")); if (whotarget[0]) { sprintf(whoredirect, "%s, your girlfriend is %s, and ", nick, whotarget); } else { dprintf(idx, "%sI didn't know you had a girlfriend, %s\n", prefix, nick); return; } } else { dprintf(idx, "%sI don't know anything about your %s, %s.\n", prefix, word1, nick); return; } } /* "your" keyword */ else if (!egg_strcasecmp(word1, "your")) { wordshift(word1, text); /* "your admin" */ if (!egg_strcasecmp(word1, "owner") || !egg_strcasecmp(word1, "admin")) { if (admin[0]) { strcpy(word2, admin); wordshift(whotarget, word2); strcat(whoredirect, "My owner is "); strcat(whoredirect, whotarget); strcat(whoredirect, ", and "); if (!egg_strcasecmp(whotarget, hand)) { strcat(whoredirect, "that's YOU"); if (!egg_strcasecmp(hand, nick)) strcat(whoredirect, "!!!"); else { strcat(whoredirect, ", "); strcat(whoredirect, nick); strcat(whoredirect, "!"); } dprintf(idx, "%s%s\n", prefix, whoredirect); return; } } else { /* owner variable munged or not set */ dprintf(idx, "%sI don't seem to recall who my owner is right now...\n", prefix); return; } } else { /* no "your" target specified */ dprintf(idx, "%sLet's not get personal, %s.\n", prefix, nick); return; } } /* Check for keyword match in the internal table */ else if (match_trigger(word1)) { sprintf(word2, "%s%s\n", prefix, match_trigger(word1)); dprintf(idx, word2, nick); return; } /* Otherwise, make the target to the first word and continue */ else strcpy(whotarget, word1); targetcont: /* Looking for ones own nick? */ if (!rfc_casecmp(nick, whotarget)) { dprintf(idx, "%s%sLooking for yourself, eh %s?\n", prefix, whoredirect, nick); return; } /* Check if nick is on a channel */ chan = chanset; while (chan) { m = ismember(chan, whotarget); if (m) { onchan = 1; sprintf(word1, "%s!%s", whotarget, m->userhost); urec = get_user_by_host(word1); if (!urec || !egg_strcasecmp(whotarget, urec->handle)) break; strcat(whoredirect, whotarget); strcat(whoredirect, " is "); strcat(whoredirect, urec->handle); strcat(whoredirect, ", and "); break; } chan = chan->next; } /* Check if nick is on a channel by xref'ing to handle */ if (!onchan) { chan = chanset; while (chan) { m = chan->channel.member; while (m && m->nick[0]) { sprintf(word2, "%s!%s", m->nick, m->userhost); urec = get_user_by_host(word2); if (urec && !egg_strcasecmp(urec->handle, whotarget)) { onchan = 1; strcat(whoredirect, whotarget); strcat(whoredirect, " is "); strcat(whoredirect, m->nick); strcat(whoredirect, ", and "); strcpy(whotarget, m->nick); break; } m = m->next; } chan = chan->next; } } /* Check if the target was on the channel, but is netsplit */ chan = findchan_by_dname(channel); if (chan) { m = ismember(chan, whotarget); if (m && chan_issplit(m)) { dprintf(idx, "%s%s%s was just here, but got netsplit.\n", prefix, whoredirect, whotarget); return; } } /* Check if the target IS on the channel */ if (chan && m) { dprintf(idx, "%s%s%s is on the channel right now!\n", prefix, whoredirect, whotarget); return; } /* Target not on this channel. Check other channels */ chan = chanset; while (chan) { m = ismember(chan, whotarget); if (m && chan_issplit(m)) { dprintf(idx, "%s%s%s was just on %s, but got netsplit.\n", prefix, whoredirect, whotarget, chan->dname); return; } if (m) { dprintf(idx, "%s%s%s is on %s right now!\n", prefix, whoredirect, whotarget, chan->dname); return; } chan = chan->next; } /* Target isn't on any of my channels. */ /* See if target matches a handle in my userlist. */ urec = get_user_by_handle(userlist, whotarget); /* No match, then bail out */ if (!urec) { dprintf(idx, "%s%sI don't know who %s is.\n", prefix, whoredirect, whotarget); return; } /* We had a userlist match to a handle */ /* Is the target currently DCC CHAT to me on the botnet? */ for (i = 0; i < dcc_total; i++) { if (dcc[i].type->flags & DCT_CHAT) { if (!egg_strcasecmp(whotarget, dcc[i].nick)) { if (!rfc_casecmp(channel, dcc[i].u.chat->con_chan) && dcc[i].u.chat->con_flags & LOG_PUBLIC) { strcat(whoredirect, whotarget); strcat(whoredirect, " is 'observing' this channel right now from my party line!"); dprintf(idx, "%s%s\n", prefix, whoredirect); } else { dprintf(idx, "%s%s%s is linked to me via DCC CHAT right now!\n", prefix, whoredirect, whotarget); } return; } } } /* Target known, but nowhere to be seen. Give last IRC and botnet time */ wordshift(word1, text); if (!egg_strcasecmp(word1, "anywhere")) cr = NULL; else for (cr = urec->chanrec; cr; cr = cr->next) { if (!rfc_casecmp(cr->channel, channel)) { if (cr->laston) { laston = cr->laston; lastonplace = channel; break; } } } if (!cr) { li = get_user(&USERENTRY_LASTON, urec); if (!li || !li->lastonplace || !li->lastonplace[0]) { dprintf(idx, "%s%sI've never seen %s around.\n", prefix, whoredirect, whotarget); return; } lastonplace = li->lastonplace; laston = li->laston; } word1[0] = 0; word2[0] = 0; work = now - laston; if (work >= 86400) { tv = work / 86400; sprintf(word2, "%lu day%s, ", tv, (tv == 1) ? "" : "s"); work = work % 86400; } if (work >= 3600) { tv = work / 3600; sprintf(word2 + strlen(word2), "%lu hour%s, ", tv, (tv == 1) ? "" : "s"); work = work % 3600; } if (work >= 60) { tv = work / 60; sprintf(word2 + strlen(word2), "%lu minute%s, ", tv, (tv == 1) ? "" : "s"); } if (!word2[0] && (work < 60)) { strcpy(word2, "just moments ago!!"); } else { strcpy(word2 + strlen(word2) - 2, " ago."); } if (lastonplace[0] && (strchr(CHANMETA, lastonplace[0]) != NULL)) sprintf(word1, "on IRC channel %s", lastonplace); else if (lastonplace[0] == '@') sprintf(word1, "on %s", lastonplace + 1); else if (lastonplace[0] != 0) sprintf(word1, "on my %s", lastonplace); else strcpy(word1, "seen"); dprintf(idx, "%s%s%s was last %s %s\n", prefix, whoredirect, whotarget, word1, word2); }