Hello, I have created a patch for the 'talk' program that does the following:
- Add the -t option for logging sessions to a transcript file - Update the argument parsing logic to use getopt() Believe it or not, there are still serious uses for 'talk', despite it being probably the most archaic form of digital communication. I've enjoyed using it for a little while now, but one feature that I think would be really handy is the ability to log sessions to a file for future reference. While I was implementing this feature, I noticed that the argument parsing logic was rather flawed. You could invoke talk with -H and -s, but not -s and -H, for example. I'm assuming this is not the intended behavior, so I also went ahead and updated the argument parsing logic to use getopt() while I was at it. Do note that this is my very first patch, and I consider it to be a rough draft. It does exactly what I need, and I'm using this code on my server, but I understand that it might not be up to the high standards of the OpenBSD project. I'm posting this patch anyway, so I can get some feedback and eventually get it into base so I don't have to manually patch the source code for every release. If you have any suggestions for improvement, just let me know. And if this isn't the right place for this kind of patch, please kindly redirect me. Thanks, Jordan Bancino Index: get_names.c =================================================================== RCS file: /cvs/src/usr.bin/talk/get_names.c,v retrieving revision 1.21 diff -u -p -u -p -r1.21 get_names.c --- get_names.c 1 Feb 2016 07:29:25 -0000 1.21 +++ get_names.c 3 May 2022 00:37:27 -0000 @@ -38,10 +38,16 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <getopt.h> #include "talk.h" -extern CTL_MSG msg; +FILE *log_file = NULL; + +static void print_usage() { + extern char *__progname; + fprintf(stderr, "usage: %s [-Hs] [-t transcript] person [ttyname]\n", __progname); +} /* * Determine the local and remote user, tty, and machines @@ -55,24 +61,41 @@ get_names(int argc, char *argv[]) char *his_tty; char *cp; char *names; + char *log_file_name = NULL; - if (argc > 1 && !strcmp(argv[1], "-H")) { - argv[1] = argv[0]; - ++argv; - --argc; - high_print = 1; + int ch; + + while ((ch = getopt(argc, argv, "Hst:")) != -1) { + switch (ch) { + case 'H': + high_print = 1; + break; + case 's': + smooth_scroll = TRUE; + break; + case 't': + log_file_name = optarg; + break; + default: + print_usage(); + exit(1); + } } - if (argc > 1 && !strcmp(argv[1], "-s")) { - argv[1] = argv[0]; - ++argv; - --argc; - smooth_scroll = TRUE; + argc -= optind; + argv += optind; + + if (log_file_name) { + log_file = fopen(log_file_name, "w"); + if (!log_file) { + fprintf(stderr, "Unable to open '%s' for writing.\n", + log_file_name); + exit(1); + } } - if ((argc < 2 ) || ('@' == argv[1][0])) { - extern char *__progname; - fprintf(stderr, "usage: %s [-Hs] person [ttyname]\n", __progname); + if ((argc < 1) || ('@' == argv[0][0])) { + print_usage(); exit(1); } if (!isatty(STDIN_FILENO)) @@ -88,7 +111,7 @@ get_names(int argc, char *argv[]) gethostname(hostname, sizeof (hostname)); my_machine_name = hostname; /* check for, and strip out, the machine name of the target */ - names = strdup(argv[1]); + names = strdup(argv[0]); if (names == NULL) errx(1, "out of memory"); for (cp = names; *cp && !strchr("@:!.", *cp); cp++) @@ -109,8 +132,8 @@ get_names(int argc, char *argv[]) } *--cp = '\0'; } - if (argc > 2) - his_tty = argv[2]; /* tty name is arg 2 */ + if (argc > 1) + his_tty = argv[1]; /* tty name is arg 2 */ else his_tty = ""; get_addrs(my_machine_name, his_machine_name); Index: io.c =================================================================== RCS file: /cvs/src/usr.bin/talk/io.c,v retrieving revision 1.20 diff -u -p -u -p -r1.20 io.c --- io.c 18 Feb 2016 21:51:20 -0000 1.20 +++ io.c 3 May 2022 00:37:27 -0000 @@ -58,6 +58,12 @@ talk(void) char buf[BUFSIZ]; int nb; + char his_buf[BUFSIZ]; + char my_buf[BUFSIZ]; + + int his_nb = 0; + int my_nb = 0; + #if defined(NCURSES_VERSION) || defined(beep) message("Connection established"); beep(); @@ -94,7 +100,31 @@ talk(void) nb = read(sockt, buf, sizeof buf); if (nb <= 0) quit("Connection closed. Exiting", 0); + display(&his_win, buf, nb); + + /* Apply this buf to the line buffer */ + if (log_file) { + int i; + for (i = 0; i < nb; i++) { + switch (buf[i]) { + case '\n': + fprintf(log_file, "%s: %.*s\n", msg.r_name, his_nb, his_buf); + fflush(log_file); + his_nb = 0; + break; + case 127: /* ASCII DEL */ + if (his_nb > 0) { + his_nb--; + } + break; + default: + his_buf[his_nb] = buf[i]; + his_nb++; + break; + } + } + } } if (fds[0].revents & POLLIN) { /* @@ -103,9 +133,33 @@ talk(void) */ ioctl(0, FIONREAD, &nb); nb = read(STDIN_FILENO, buf, nb); + display(&my_win, buf, nb); /* might lose data here because sockt is non-blocking */ write(sockt, buf, nb); + + /* Apply this buf to the line buffer */ + if (log_file) { + int i; + for (i = 0; i < nb; i++) { + switch (buf[i]) { + case '\n': + fprintf(log_file, "%s: %.*s\n", msg.l_name, my_nb, my_buf); + fflush(log_file); + my_nb = 0; + break; + case 127: /* ASCII DEL */ + if (my_nb > 0) { + my_nb--; + } + break; + default: + my_buf[my_nb] = buf[i]; + my_nb++; + break; + } + } + } } } } Index: talk.1 =================================================================== RCS file: /cvs/src/usr.bin/talk/talk.1,v retrieving revision 1.27 diff -u -p -u -p -r1.27 talk.1 --- talk.1 25 May 2017 20:25:50 -0000 1.27 +++ talk.1 3 May 2022 00:37:27 -0000 @@ -39,6 +39,7 @@ .Sh SYNOPSIS .Nm talk .Op Fl Hs +.Op Fl t Ar transcript .Ar person .Op Ar ttyname .Sh DESCRIPTION @@ -58,6 +59,21 @@ Use smooth scrolling in the window. The default is to clear the next two rows and jump from the bottom of the window to the top. +.It Fl t Ar transcript +Log the entire +.Nm +session to +.Ar transcript. +.Nm +will interleave messages from each user by line. +Essentially, each line is buffered, and whenever a user presses enter, +their line is put into the transcript. This allows users to write at +the same time, and edit their lines normally, while only the final +line that they commit to the terminal ends up in the transcript. +Note that the user must press enter for the line to be added to the +transcript. This is especially important to note when closing a +session; if either user did not press enter before the session is +ended, the final line will not be flushed to the transcript. .It Ar person If you wish to talk to someone on your own machine, then .Ar person @@ -151,10 +167,13 @@ specification, though its presence is optional. .Pp The flags -.Op Fl Hs +.Op Fl Hst are extensions to that specification. .Sh HISTORY The .Nm command appeared in .Bx 4.2 . +It was updated to add support for +.Op Fl t +by Jordan Bancino in OpenBSD 7.2. Index: talk.c =================================================================== RCS file: /cvs/src/usr.bin/talk/talk.c,v retrieving revision 1.12 diff -u -p -u -p -r1.12 talk.c --- talk.c 8 Mar 2016 20:07:46 -0000 1.12 +++ talk.c 3 May 2022 00:37:27 -0000 @@ -54,7 +54,7 @@ int main(int argc, char *argv[]) { - if (pledge("stdio rpath inet dns getpw tty", NULL) == -1) + if (pledge("stdio rpath wpath cpath fattr inet dns getpw tty", NULL) == -1) err(1, "pledge"); get_names(argc, argv); Index: talk.h =================================================================== RCS file: /cvs/src/usr.bin/talk/talk.h,v retrieving revision 1.12 diff -u -p -u -p -r1.12 talk.h --- talk.h 1 Feb 2016 07:29:25 -0000 1.12 +++ talk.h 3 May 2022 00:37:27 -0000 @@ -49,6 +49,8 @@ extern volatile sig_atomic_t gotwinch; extern char *current_state; extern int current_line; +extern FILE *log_file; + typedef struct xwin { WINDOW *x_win; int x_nlines; @@ -63,6 +65,8 @@ typedef struct xwin { extern xwin_t my_win; extern xwin_t his_win; extern WINDOW *line_win; + +extern CTL_MSG msg; void announce_invite(void); int check_local(void);