Add base64 decode for translation and right-align clock in status bar
This commit is contained in:
@@ -218,6 +218,77 @@ static void config_save(void)
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/* Base64 decode: returns decoded length, or -1 if not valid base64 */
|
||||
static int base64_decode(const char *in, size_t in_len, char *out, size_t out_size)
|
||||
{
|
||||
static const int T[256] = {
|
||||
['A']=0,['B']=1,['C']=2,['D']=3,['E']=4,['F']=5,['G']=6,['H']=7,
|
||||
['I']=8,['J']=9,['K']=10,['L']=11,['M']=12,['N']=13,['O']=14,['P']=15,
|
||||
['Q']=16,['R']=17,['S']=18,['T']=19,['U']=20,['V']=21,['W']=22,['X']=23,
|
||||
['Y']=24,['Z']=25,['a']=26,['b']=27,['c']=28,['d']=29,['e']=30,['f']=31,
|
||||
['g']=32,['h']=33,['i']=34,['j']=35,['k']=36,['l']=37,['m']=38,['n']=39,
|
||||
['o']=40,['p']=41,['q']=42,['r']=43,['s']=44,['t']=45,['u']=46,['v']=47,
|
||||
['w']=48,['x']=49,['y']=50,['z']=51,['0']=52,['1']=53,['2']=54,['3']=55,
|
||||
['4']=56,['5']=57,['6']=58,['7']=59,['8']=60,['9']=61,['+']=62,['/']=63,
|
||||
};
|
||||
/* Strip trailing padding for length calc */
|
||||
size_t pad = 0;
|
||||
while (in_len > 0 && in[in_len - 1] == '=') { pad++; in_len--; }
|
||||
if (in_len < 4) return -1;
|
||||
size_t out_len = in_len * 3 / 4;
|
||||
if (out_len >= out_size) return -1;
|
||||
|
||||
size_t o = 0;
|
||||
for (size_t i = 0; i < in_len; i += 4) {
|
||||
int n = (int)(in_len - i);
|
||||
if (n < 2) break;
|
||||
unsigned int a = T[(unsigned char)in[i]];
|
||||
unsigned int b = T[(unsigned char)in[i+1]];
|
||||
out[o++] = (a << 2) | (b >> 4);
|
||||
if (n > 2 && i + 2 < in_len + pad) {
|
||||
unsigned int c = (i+2 < in_len) ? T[(unsigned char)in[i+2]] : 0;
|
||||
out[o++] = (b << 4) | (c >> 2);
|
||||
if (n > 3 && i + 3 < in_len + pad) {
|
||||
unsigned int d = (i+3 < in_len) ? T[(unsigned char)in[i+3]] : 0;
|
||||
out[o++] = (c << 6) | d;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Adjust for padding */
|
||||
if (pad == 1 && o > 0) o--;
|
||||
if (pad == 2 && o > 0) o--;
|
||||
out[o] = '\0';
|
||||
return (int)o;
|
||||
}
|
||||
|
||||
/* Check if text looks like base64 and decode it. Returns 1 if decoded. */
|
||||
static int try_base64_decode(const char *text, char *out, size_t out_size)
|
||||
{
|
||||
size_t len = strlen(text);
|
||||
if (len < 8 || len > 1000) return 0;
|
||||
/* Must be valid base64 chars only */
|
||||
size_t i;
|
||||
for (i = 0; i < len; i++) {
|
||||
char c = text[i];
|
||||
if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') || c == '+' || c == '/' || c == '='))
|
||||
return 0;
|
||||
}
|
||||
/* Length must be multiple of 4 */
|
||||
if (len % 4 != 0) return 0;
|
||||
int n = base64_decode(text, len, out, out_size);
|
||||
if (n < 4) return 0;
|
||||
/* Check that result looks like text (mostly printable) */
|
||||
int printable = 0;
|
||||
for (int j = 0; j < n; j++) {
|
||||
unsigned char c = (unsigned char)out[j];
|
||||
if ((c >= 0x20 && c <= 0x7e) || c == '\n' || c == '\r' || c == '\t' || c >= 0x80)
|
||||
printable++;
|
||||
}
|
||||
if (printable * 100 / n < 80) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int needs_translation(const char *text)
|
||||
{
|
||||
if (!ai_cfg.enabled || !translate_enabled) return 0;
|
||||
@@ -461,6 +532,22 @@ static void draw_statusbar(void)
|
||||
size_t blen = strlen(bar);
|
||||
snprintf(bar + blen, sizeof(bar) - blen, "%s", act);
|
||||
|
||||
/* Right-align timestamp */
|
||||
time_t now = time(NULL);
|
||||
struct tm *tm = localtime(&now);
|
||||
char rhs[64];
|
||||
snprintf(rhs, sizeof(rhs), "[Holck Mirk - %02d%02d %02d:%02d]",
|
||||
tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
|
||||
size_t bar_len = strlen(bar);
|
||||
size_t rhs_len = strlen(rhs);
|
||||
if (bar_len + rhs_len < (size_t)term_cols) {
|
||||
size_t pad = term_cols - rhs_len;
|
||||
while (bar_len < pad)
|
||||
bar[bar_len++] = ' ';
|
||||
memcpy(bar + pad, rhs, rhs_len);
|
||||
bar[term_cols] = '\0';
|
||||
}
|
||||
|
||||
/* Status bar on second-to-last row */
|
||||
printf("\033[%d;1H\033[7m%-*.*s\033[0m",
|
||||
term_rows - 1, term_cols, term_cols, bar);
|
||||
@@ -995,12 +1082,24 @@ static void handle_line(char *line)
|
||||
} else if (strcasecmp(target, nick) == 0) {
|
||||
wprintf(WL_MSG, "<%s> %s\n", sender, text);
|
||||
pm_nick_add(sender);
|
||||
if (needs_translation(text))
|
||||
char b64dec[1024];
|
||||
if (try_base64_decode(text, b64dec, sizeof(b64dec))) {
|
||||
if (needs_translation(b64dec))
|
||||
translate_async(b64dec, WL_MSG, NULL);
|
||||
else
|
||||
wprintf(WL_MSG, " \033[3m[b64: %s]\033[0m\n", b64dec);
|
||||
} else if (needs_translation(text))
|
||||
translate_async(text, WL_MSG, NULL);
|
||||
} else {
|
||||
int lvl = chan_to_level(target);
|
||||
wprintf(lvl, "<%s> %s\n", sender, text);
|
||||
if (needs_translation(text))
|
||||
char b64dec2[1024];
|
||||
if (try_base64_decode(text, b64dec2, sizeof(b64dec2))) {
|
||||
if (needs_translation(b64dec2))
|
||||
translate_async(b64dec2, lvl, translate_public ? target : NULL);
|
||||
else
|
||||
wprintf(lvl, " \033[3m[b64: %s]\033[0m\n", b64dec2);
|
||||
} else if (needs_translation(text))
|
||||
translate_async(text, lvl, translate_public ? target : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user