sirc

A simple tui multi server irc client
git clone git://git.emmett1.my/sirc.git
Log | Files | Refs | README | LICENSE

commit 5a43139f7520c2168c39dc9792aa9ecef510a89a
parent f52d54ccc7383af9d029fb75efb91b7e20540c5f
Author: emmett1 <me@emmett1.my>
Date:   Tue,  7 Apr 2026 08:08:37 +0800

fix sasl authenticate again

Diffstat:
Msirc.c | 59+++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 39 insertions(+), 20 deletions(-)

diff --git a/sirc.c b/sirc.c @@ -196,6 +196,7 @@ typedef struct { int reconnect_pending; pthread_t reconnect_tid; + int sasl_auth_sent; /* guard: only send AUTHENTICATE once per session */ /* per-server event pipe */ int evpipe[2]; @@ -579,17 +580,18 @@ static const char b64tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static void base64_encode(const unsigned char *in, int inlen, char *out) { - int i=0, j=0; - while (i < inlen) { - unsigned int a=i<inlen?(unsigned char)in[i++]:0; - unsigned int b=i<inlen?(unsigned char)in[i++]:0; - unsigned int c=i<inlen?(unsigned char)in[i++]:0; - unsigned int n=(a<<16)|(b<<8)|c; - out[j++]=b64tab[(n>>18)&63]; out[j++]=b64tab[(n>>12)&63]; - out[j++]=(i-2<=inlen)?b64tab[(n>>6)&63]:'='; - out[j++]=(i-1<=inlen)?b64tab[n&63]:'='; - } - out[j]='\0'; + int j = 0; + for (int i = 0; i < inlen; i += 3) { + unsigned int a = (unsigned char)in[i]; + unsigned int b = (i+1 < inlen) ? (unsigned char)in[i+1] : 0; + unsigned int c = (i+2 < inlen) ? (unsigned char)in[i+2] : 0; + unsigned int n = (a << 16) | (b << 8) | c; + out[j++] = b64tab[(n >> 18) & 63]; + out[j++] = b64tab[(n >> 12) & 63]; + out[j++] = (i+1 < inlen) ? b64tab[(n >> 6) & 63] : '='; + out[j++] = (i+2 < inlen) ? b64tab[n & 63] : '='; + } + out[j] = '\0'; } /* ── IRC line handler (net thread — uses si to tag every event) ────────────── */ @@ -604,18 +606,33 @@ static void handle_irc_line(int si, const char *raw) { return; } - /* SASL */ + /* SASL / CAP negotiation */ if (strcmp(m.cmd,"CAP")==0) { char sub[16]=""; if (m.nparams>=2) str_upper(sub, m.params[1], sizeof(sub)); - if (strcmp(sub,"ACK")==0) { - /* trail or last param may contain "sasl" */ - const char *caps = m.trail[0] ? m.trail : m.params[m.nparams-1]; + else if (m.nparams>=1) str_upper(sub, m.params[0], sizeof(sub)); + + /* log all CAP lines to status for visibility */ + char capdbg[MAX_LINE]; + snprintf(capdbg,sizeof(capdbg),"[CAP] %s",raw); + ev_simple(EV_STATUS, si, NULL, NULL, capdbg); + + if (strcmp(sub,"LS")==0) { + /* server advertising capabilities -- request sasl */ + srv_send_raw(si, "CAP REQ :sasl"); + } else if (strcmp(sub,"ACK")==0) { + const char *caps = m.trail[0] ? m.trail : (m.nparams>0?m.params[m.nparams-1]:""); if (strstr(caps,"sasl")) { - srv_send_raw(si, "AUTHENTICATE PLAIN"); + if (!s->sasl_auth_sent) { + s->sasl_auth_sent = 1; + srv_send_raw(si, "AUTHENTICATE PLAIN"); + } + } else { + srv_send_raw(si, "CAP END"); } } else if (strcmp(sub,"NAK")==0) { - ev_simple(EV_ERROR, si, NULL, NULL, "Server rejected SASL CAP."); + ev_simple(EV_ERROR, si, NULL, NULL, "Server rejected SASL CAP -- connecting without SASL."); + srv_send_raw(si, "CAP END"); srv_sendf(si, "NICK %s", s->nick); srv_sendf(si, "USER %s 0 * :sirc", s->nick); } @@ -991,9 +1008,11 @@ static void *net_thread(void *arg) { } int sasl_pending=(s->sasl_user[0]&&s->sasl_pass[0])?1:0; - if (sasl_pending) - srv_send_raw(si,"CAP REQ :sasl"); - else { + s->sasl_auth_sent = 0; + if (sasl_pending) { + /* CAP LS 302: proper negotiation, handler sends CAP REQ :sasl on LS reply */ + srv_send_raw(si,"CAP LS 302"); + } else { srv_sendf(si,"NICK %s",s->nick); srv_sendf(si,"USER %s 0 * :sirc",s->nick); }