--- a/libpurple/protocols/zephyr/zephyr.c Mon Jan 11 01:51:14 2021 -0600
+++ b/libpurple/protocols/zephyr/zephyr.c Mon Jan 11 20:11:21 2021 -0600
@@ -63,6 +63,7 @@
typedef struct _zephyr_account zephyr_account;
typedef gssize (*PollableInputStreamReadFunc)(GPollableInputStream *stream, void *bufcur, GError **error);
+typedef gboolean (*ZephyrLoginFunc)(zephyr_account *zephyr); PURPLE_ZEPHYR_NONE, /* Non-kerberized ZEPH0.2 */
@@ -111,8 +112,10 @@
#define z_call_s(func, err) if (func != ZERR_NONE) {\
- purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, err);\
+ purple_connection_error(\ + purple_account_get_connection(zephyr->account),\ + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, err);\ @@ -1196,17 +1199,228 @@
+get_tzc_process(const zephyr_account *zephyr) + GSubprocess *tzc_process = NULL; + gchar **tzc_cmd_array = NULL; + gboolean found_ps = FALSE; + /* tzc_command should really be of the form + ssh username@hostname pathtotzc -e %s + -- this should not require a password, and ideally should be + fsh username@hostname pathtotzc -e %s + tzc_cmd = purple_account_get_string(zephyr->account, "tzc_command", "/usr/bin/tzc -e %s"); + if (!g_shell_parse_argv(tzc_cmd, NULL, &tzc_cmd_array, &error)) { + purple_debug_error("zephyr", "Unable to parse tzc_command: %s", error->message); + purple_connection_error( + purple_account_get_connection(zephyr->account), + PURPLE_CONNECTION_ERROR_INVALID_SETTINGS, + "invalid tzc_command setting"); + for (i = 0; tzc_cmd_array[i] != NULL; i++) { + if (purple_strequal(tzc_cmd_array[i], "%s")) { + g_free(tzc_cmd_array[i]); + tzc_cmd_array[i] = g_strdup(zephyr->exposure); + purple_debug_error("zephyr", "tzc exited early"); + purple_connection_error( + purple_account_get_connection(zephyr->account), + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + "invalid output by tzc (or bad parsing code)"); + g_strfreev(tzc_cmd_array); + tzc_process = g_subprocess_newv( + (const gchar *const *)tzc_cmd_array, + G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE, + if (tzc_process == NULL) { + purple_debug_error("zephyr", "tzc exited early: %s", error->message); + purple_connection_error( + purple_account_get_connection(zephyr->account), + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + "invalid output by tzc (or bad parsing code)"); + g_strfreev(tzc_cmd_array); +get_paren_level(gint paren_level, gchar ch) + case '(': return paren_level + 1; + case ')': return paren_level - 1; + default: return paren_level; +get_zephyr_realm(PurpleAccount *account, const gchar *local_realm) + const char *realm = purple_account_get_string(account, "realm", ""); + g_strlcpy(__Zephyr_realm, realm, REALM_SZ - 1); + return g_strdup(realm); +parse_tzc_login_data(zephyr_account *zephyr, const gchar *buf, gint buflen) + gchar *str = g_strndup(buf, buflen); + purple_debug_info("zephyr", "tempstr parsed"); + /* str should now be a string containing all characters from + * buf after the first ( to the one before the last paren ). + * We should have the following possible lisp strings but we don't care + * (tzcspew . start) (version . "something") (pid . number) + * We care about 'zephyrid . "username@REALM.NAME"' and + * 'exposure . "SOMETHING"' */ + if (!g_ascii_strncasecmp(str, "zephyrid", 8)) { + purple_debug_info("zephyr", "zephyrid found"); + strv = g_strsplit(str + 8, "\"", -1); + username = strv[1] ? strv[1] : ""; + zephyr->username = g_strdup(username); + at = strchr(username, '@'); + zephyr->realm = g_strdup(at + 1); + zephyr->realm = get_zephyr_realm(zephyr->account, "local-realm"); + purple_debug_info("zephyr", "something that's not zephyr id found %s", str); + /* We don't care about anything else yet */ +login_tzc(zephyr_account *zephyr) + const gchar *bufend = NULL; + zephyr->tzc_proc = get_tzc_process(zephyr); + if (zephyr->tzc_proc == NULL) { + zephyr->tzc_stdin = g_subprocess_get_stdin_pipe(zephyr->tzc_proc); + zephyr->tzc_stdout = g_subprocess_get_stdout_pipe(zephyr->tzc_proc); + purple_debug_info("zephyr", "about to read from tzc"); + buf = read_from_tzc(zephyr, pollable_input_stream_read_with_timeout); + bufend = buf + strlen(buf); + /* ignore all tzcoutput till we've received the first ( */ + while (ptr < bufend && (*ptr != '(')) { + purple_connection_error( + purple_account_get_connection(zephyr->account), + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + "invalid output by tzc (or bad parsing code)"); + parenlevel = get_paren_level(parenlevel, *ptr); + purple_debug_info("zephyr", "tzc parenlevel is %d", parenlevel); + /* Search for next beginning (, or for the ending */ + } while ((ptr < bufend) && (*ptr != '(') && (*ptr != ')')); + purple_debug_error("zephyr", "tzc parsing error"); + (foo . bar ) or (foo . "bar") or (foo . chars) or (foo . numbers) or (foo . () ) + Parse all the data between the first and last f, and move past ) + parenlevel = get_paren_level(parenlevel, *ptr); + } while (parenlevel > 1); + parse_tzc_login_data(zephyr, tmp + 1, ptr - tmp); + purple_debug_info("zephyr", "parenlevel is not 1 or 2"); + /* This shouldn't be happening */ + } while (ptr < bufend && parenlevel != 0); + purple_debug_info("zephyr", "tzc startup done"); +login_zeph02(zephyr_account *zephyr) + /* XXX z_call_s should actually try to report the com_err determined error */ + z_call_s(ZInitialize(), "Couldn't initialize zephyr"); + z_call_s(ZOpenPort(&(zephyr->port)), "Couldn't open port"); + z_call_s(ZSetLocation(zephyr->exposure), "Couldn't set location"); + zephyr->username = g_strdup(ZGetSender()); + zephyr->realm = get_zephyr_realm(zephyr->account, ZGetRealm()); static void zephyr_login(PurpleAccount * account)
GSourceFunc check_notify;
gc = purple_account_get_connection(account);
- read_anyone = purple_account_get_bool(account, "read_anyone", TRUE);
- read_zsubs = purple_account_get_bool(account, "read_zsubs", TRUE);
username = purple_account_get_username(account);
@@ -1220,224 +1434,20 @@
zephyr->account = account;
zephyr->exposure = get_zephyr_exposure(account);
- if (purple_account_get_bool(account, "use_tzc", 0)) {
+ if (purple_account_get_bool(account, "use_tzc", FALSE)) { zephyr->connection_type = PURPLE_ZEPHYR_TZC;
check_notify = check_notify_tzc;
zephyr->connection_type = PURPLE_ZEPHYR_KRB4;
check_notify = check_notify_zeph02;
zephyr->encoding = (char *)purple_account_get_string(account, "encoding", ZEPHYR_FALLBACK_CHARSET);
purple_connection_update_progress(gc, _("Connecting"), 0, 8);
- /* XXX z_call_s should actually try to report the com_err determined error */
- gboolean found_ps = FALSE;
- gchar **tzc_cmd_array = NULL;
- /* tzc_command should really be of the form
- ssh username@hostname pathtotzc -e %s
- -- this should not require a password, and ideally should be
- fsh username@hostname pathtotzc -e %s
- if (!g_shell_parse_argv(purple_account_get_string(
- account, "tzc_command", "/usr/bin/tzc -e %s"),
- NULL, &tzc_cmd_array, &error)) {
- purple_debug_error("zephyr", "Unable to parse tzc_command: %s",
- purple_connection_error(gc,
- PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
- "invalid tzc_command setting");
- for (i = 0; tzc_cmd_array[i] != NULL; i++) {
- if (purple_strequal(tzc_cmd_array[i], "%s")) {
- g_free(tzc_cmd_array[i]);
- tzc_cmd_array[i] = g_strdup(zephyr->exposure);
- purple_debug_error("zephyr", "tzc exited early");
- purple_connection_error(
- gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- "invalid output by tzc (or bad parsing code)");
- g_strfreev(tzc_cmd_array);
- zephyr->tzc_proc = g_subprocess_newv(
- (const gchar *const *)tzc_cmd_array,
- G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE,
- g_strfreev(tzc_cmd_array);
- if (zephyr->tzc_proc == NULL) {
- purple_debug_error("zephyr", "tzc exited early: %s",
- purple_connection_error(
- gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- "invalid output by tzc (or bad parsing code)");
- zephyr->tzc_stdin = g_subprocess_get_stdin_pipe(zephyr->tzc_proc);
- zephyr->tzc_stdout = g_subprocess_get_stdout_pipe(zephyr->tzc_proc);
- purple_debug_info("zephyr", "about to read from tzc");
- buf = read_from_tzc(zephyr, pollable_input_stream_read_with_timeout);
- bufcur = buf + strlen(buf);
- /* ignore all tzcoutput till we've received the first (*/
- while (ptr < bufcur && (*ptr != '(')) {
- purple_connection_error(
- gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- "invalid output by tzc (or bad parsing code)");
- } else if (*ptr == ')') {
- purple_debug_info("zephyr", "tzc parenlevel is %d", parenlevel);
- /* Search for next beginning (, or for the ending */
- while ((*ptr != '(') && (*ptr != ')') && (ptr < bufcur)) {
- purple_debug_error("zephyr", "tzc parsing error");
- (foo . bar ) or (foo . "bar") or (foo . chars) or (foo . numbers) or (foo . () )
- Parse all the data between the first and last f, and move past )
- tempstr = g_new0(gchar, 20000);
- purple_debug_info("zephyr", "tempstr parsed");
- /* tempstr should now be a i-length string containing all
- * characters from that after the first ( to the one before
- * the last paren ). We should have the following possible
- * lisp strings but we don't care
- * (tzcspew . start) (version . "something") (pid . number)
- * We care about 'zephyrid . "username@REALM.NAME"' and
- * 'exposure . "SOMETHING"' */
- if (!g_ascii_strncasecmp(tempstr,"zephyrid",8)) {
- gchar* username = g_malloc0(100);
- purple_debug_info("zephyr", "zephyrid found");
- while (i < 20000 && tempstr[i] != '"') {
- while (i < 20000 && tempstr[i] != '"') {
- username[username_idx++] = tempstr[i++];
- zephyr->username = g_strdup_printf("%s",username);
- if ((realm = strchr(username,'@')))
- zephyr->realm = g_strdup_printf("%s",realm+1);
- realm = purple_account_get_string(account, "realm", "");
- zephyr->realm = g_strdup(realm);
- g_strlcpy(__Zephyr_realm,
- (const gchar *)zephyr->realm,
- zephyr->realm = g_strdup("local-realm");
- "something that's not zephyr id found %s",
- /* We don't care about anything else yet */
- purple_debug_info("zephyr", "parenlevel is not 1 or 2");
- /* This shouldn't be happening */
- } /* while (ptr < bufcur) */
- purple_debug_info("zephyr", "tzc startup done");
- else if ( use_zeph02(zephyr)) {
- z_call_s(ZInitialize(), "Couldn't initialize zephyr");
- z_call_s(ZOpenPort(&(zephyr->port)), "Couldn't open port");
- z_call_s(ZSetLocation((char *)zephyr->exposure), "Couldn't set location");
- realm = purple_account_get_string(account, "realm", "");
- zephyr->realm = g_strdup(realm);
- g_strlcpy(__Zephyr_realm, (const char*)zephyr->realm, REALM_SZ-1);
- zephyr->username = g_strdup(ZGetSender());
- /* zephyr->realm = g_strdup(ZGetRealm()); */
- purple_debug_info("zephyr","realm: %s\n",zephyr->realm);
- purple_connection_error(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, "Only ZEPH0.2 supported currently");
purple_debug_info("zephyr","does it get here\n");
@@ -1459,14 +1469,15 @@
purple_connection_set_state(gc, PURPLE_CONNECTION_CONNECTED);
+ if (purple_account_get_bool(account, "read_anyone", TRUE)) {
+ if (purple_account_get_bool(account, "read_zsubs", TRUE)) { zephyr->nottimer = g_timeout_add(100, check_notify, gc);
zephyr->loctimer = g_timeout_add_seconds(20, check_loc, gc);
static void write_zsubs(zephyr_account *zephyr)