Scan messages for URLs

master
C. McEnroe 2020-02-08 18:29:01 -05:00
parent 156282c95d
commit f502260dd0
6 changed files with 133 additions and 3 deletions

View File

@ -11,6 +11,7 @@ OBJS += edit.o
OBJS += handle.o OBJS += handle.o
OBJS += irc.o OBJS += irc.o
OBJS += ui.o OBJS += ui.o
OBJS += url.o
dev: tags all dev: tags all

View File

@ -156,6 +156,15 @@ Close the named, numbered or current window.
Toggle logging in the Toggle logging in the
.Sy <debug> .Sy <debug>
window. window.
.It Ic /open Op Ar count
Open each of
.Ar count
most recent URLs.
.It Ic /open Ar nick | substring
Open the most recent URL from
.Ar nick
or matching
.Ar substring .
.It Ic /window Ar name .It Ic /window Ar name
Switch to window by name. Switch to window by name.
.It Ic /window Ar num , Ic / Ns Ar num .It Ic /window Ar num , Ic / Ns Ar num

4
chat.h
View File

@ -169,6 +169,10 @@ void completeClear(size_t id);
size_t completeID(const char *str); size_t completeID(const char *str);
enum Color completeColor(size_t id, const char *str); enum Color completeColor(size_t id, const char *str);
void urlScan(size_t id, const char *nick, const char *mesg);
void urlOpenCount(size_t id, size_t count);
void urlOpenMatch(size_t id, const char *str);
FILE *configOpen(const char *path, const char *mode); FILE *configOpen(const char *path, const char *mode);
int getopt_config( int getopt_config(
int argc, char *const *argv, int argc, char *const *argv,

View File

@ -144,6 +144,16 @@ static void commandClose(size_t id, char *params) {
} }
} }
static void commandOpen(size_t id, char *params) {
if (!params) {
urlOpenCount(id, 1);
} else if (isdigit(params[0])) {
urlOpenCount(id, strtoul(params, NULL, 10));
} else {
urlOpenMatch(id, params);
}
}
static const struct Handler { static const struct Handler {
const char *cmd; const char *cmd;
Command *fn; Command *fn;
@ -155,6 +165,7 @@ static const struct Handler {
{ "/names", commandNames }, { "/names", commandNames },
{ "/nick", commandNick }, { "/nick", commandNick },
{ "/notice", commandNotice }, { "/notice", commandNotice },
{ "/open", commandOpen },
{ "/part", commandPart }, { "/part", commandPart },
{ "/query", commandQuery }, { "/query", commandQuery },
{ "/quit", commandQuit }, { "/quit", commandQuit },

View File

@ -193,6 +193,7 @@ static void handleReplyISupport(struct Message *msg) {
static void handleReplyMOTD(struct Message *msg) { static void handleReplyMOTD(struct Message *msg) {
require(msg, false, 2); require(msg, false, 2);
char *line = msg->params[1]; char *line = msg->params[1];
urlScan(Network, msg->nick, line);
if (!strncmp(line, "- ", 2)) { if (!strncmp(line, "- ", 2)) {
uiFormat(Network, Cold, tagTime(msg), "\3%d-\3\t%s", Gray, &line[2]); uiFormat(Network, Cold, tagTime(msg), "\3%d-\3\t%s", Gray, &line[2]);
} else { } else {
@ -227,6 +228,7 @@ static void handlePart(struct Message *msg) {
completeClear(id); completeClear(id);
} }
completeRemove(id, msg->nick); completeRemove(id, msg->nick);
urlScan(id, msg->nick, msg->params[1]);
uiFormat( uiFormat(
id, Cold, tagTime(msg), id, Cold, tagTime(msg),
"\3%02d%s\3\tleaves \3%02d%s\3%s%s", "\3%02d%s\3\tleaves \3%02d%s\3%s%s",
@ -241,6 +243,7 @@ static void handleKick(struct Message *msg) {
size_t id = idFor(msg->params[0]); size_t id = idFor(msg->params[0]);
bool kicked = self.nick && !strcmp(msg->params[1], self.nick); bool kicked = self.nick && !strcmp(msg->params[1], self.nick);
completeTouch(id, msg->nick, hash(msg->user)); completeTouch(id, msg->nick, hash(msg->user));
urlScan(id, msg->nick, msg->params[2]);
uiFormat( uiFormat(
id, (kicked ? Hot : Cold), tagTime(msg), id, (kicked ? Hot : Cold), tagTime(msg),
"%s\3%02d%s\17\tkicks \3%02d%s\3 out of \3%02d%s\3%s%s", "%s\3%02d%s\17\tkicks \3%02d%s\3 out of \3%02d%s\3%s%s",
@ -275,6 +278,7 @@ static void handleQuit(struct Message *msg) {
require(msg, true, 0); require(msg, true, 0);
size_t id; size_t id;
while (None != (id = completeID(msg->nick))) { while (None != (id = completeID(msg->nick))) {
urlScan(id, msg->nick, msg->params[0]);
uiFormat( uiFormat(
id, Cold, tagTime(msg), id, Cold, tagTime(msg),
"\3%02d%s\3\tleaves%s%s", "\3%02d%s\3\tleaves%s%s",
@ -333,8 +337,10 @@ static void handleReplyTopic(struct Message *msg) {
require(msg, false, 3); require(msg, false, 3);
if (!replies.topic) return; if (!replies.topic) return;
replies.topic--; replies.topic--;
size_t id = idFor(msg->params[1]);
urlScan(id, NULL, msg->params[2]);
uiFormat( uiFormat(
idFor(msg->params[1]), Cold, tagTime(msg), id, Cold, tagTime(msg),
"The sign in \3%02d%s\3 reads: %s", "The sign in \3%02d%s\3 reads: %s",
hash(msg->params[1]), msg->params[1], msg->params[2] hash(msg->params[1]), msg->params[1], msg->params[2]
); );
@ -342,16 +348,18 @@ static void handleReplyTopic(struct Message *msg) {
static void handleTopic(struct Message *msg) { static void handleTopic(struct Message *msg) {
require(msg, true, 2); require(msg, true, 2);
size_t id = idFor(msg->params[0]);
if (msg->params[1][0]) { if (msg->params[1][0]) {
urlScan(id, msg->nick, msg->params[1]);
uiFormat( uiFormat(
idFor(msg->params[0]), Warm, tagTime(msg), id, Warm, tagTime(msg),
"\3%02d%s\3\tplaces a new sign in \3%02d%s\3: %s", "\3%02d%s\3\tplaces a new sign in \3%02d%s\3: %s",
hash(msg->user), msg->nick, hash(msg->params[0]), msg->params[0], hash(msg->user), msg->nick, hash(msg->params[0]), msg->params[0],
msg->params[1] msg->params[1]
); );
} else { } else {
uiFormat( uiFormat(
idFor(msg->params[0]), Warm, tagTime(msg), id, Warm, tagTime(msg),
"\3%02d%s\3\tremoves the sign in \3%02d%s\3", "\3%02d%s\3\tremoves the sign in \3%02d%s\3",
hash(msg->user), msg->nick, hash(msg->params[0]), msg->params[0] hash(msg->user), msg->nick, hash(msg->params[0]), msg->params[0]
); );
@ -400,6 +408,7 @@ static void handlePrivmsg(struct Message *msg) {
bool action = isAction(msg); bool action = isAction(msg);
bool mention = !mine && isMention(msg); bool mention = !mine && isMention(msg);
if (!notice && !mine) completeTouch(id, msg->nick, hash(msg->user)); if (!notice && !mine) completeTouch(id, msg->nick, hash(msg->user));
urlScan(id, msg->nick, msg->params[1]);
if (notice) { if (notice) {
uiFormat( uiFormat(
id, Warm, tagTime(msg), id, Warm, tagTime(msg),

96
url.c 100644
View File

@ -0,0 +1,96 @@
/* Copyright (C) 2020 C. McEnroe <june@causal.agency>
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <err.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include "chat.h"
static const char *Pattern = {
"("
"cvs|"
"ftp|"
"git|"
"gopher|"
"http|"
"https|"
"irc|"
"ircs|"
"magnet|"
"sftp|"
"ssh|"
"svn|"
"telnet|"
"vnc"
")"
":[^[:space:]>\"]+"
};
static regex_t Regex;
static void compile(void) {
static bool compiled;
if (compiled) return;
compiled = true;
int error = regcomp(&Regex, Pattern, REG_EXTENDED);
if (!error) return;
char buf[256];
regerror(error, &Regex, buf, sizeof(buf));
errx(EX_SOFTWARE, "regcomp: %s: %s", buf, Pattern);
}
enum { Cap = 32 };
static struct {
size_t ids[Cap];
char *nicks[Cap];
char *urls[Cap];
size_t len;
} ring;
static void push(size_t id, const char *nick, const char *url, size_t len) {
size_t i = ring.len++ % Cap;
free(ring.nicks[i]);
free(ring.urls[i]);
ring.ids[i] = id;
ring.nicks[i] = NULL;
if (nick) {
ring.nicks[i] = strdup(nick);
if (!ring.nicks[i]) err(EX_OSERR, "strdup");
}
ring.urls[i] = strndup(url, len);
if (!ring.urls[i]) err(EX_OSERR, "strndup");
}
void urlScan(size_t id, const char *nick, const char *mesg) {
if (!mesg) return;
compile();
regmatch_t match = {0};
for (const char *ptr = mesg; *ptr; ptr += match.rm_eo) {
if (regexec(&Regex, ptr, 1, &match, 0)) break;
push(id, nick, &ptr[match.rm_so], match.rm_eo - match.rm_so);
}
}
void urlOpenCount(size_t id, size_t count) {
// TODO
}
void urlOpenMatch(size_t id, const char *str) {
// TODO
}