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);
|
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)
|
static int needs_translation(const char *text)
|
||||||
{
|
{
|
||||||
if (!ai_cfg.enabled || !translate_enabled) return 0;
|
if (!ai_cfg.enabled || !translate_enabled) return 0;
|
||||||
@@ -461,6 +532,22 @@ static void draw_statusbar(void)
|
|||||||
size_t blen = strlen(bar);
|
size_t blen = strlen(bar);
|
||||||
snprintf(bar + blen, sizeof(bar) - blen, "%s", act);
|
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 */
|
/* Status bar on second-to-last row */
|
||||||
printf("\033[%d;1H\033[7m%-*.*s\033[0m",
|
printf("\033[%d;1H\033[7m%-*.*s\033[0m",
|
||||||
term_rows - 1, term_cols, term_cols, bar);
|
term_rows - 1, term_cols, term_cols, bar);
|
||||||
@@ -995,12 +1082,24 @@ static void handle_line(char *line)
|
|||||||
} else if (strcasecmp(target, nick) == 0) {
|
} else if (strcasecmp(target, nick) == 0) {
|
||||||
wprintf(WL_MSG, "<%s> %s\n", sender, text);
|
wprintf(WL_MSG, "<%s> %s\n", sender, text);
|
||||||
pm_nick_add(sender);
|
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);
|
translate_async(text, WL_MSG, NULL);
|
||||||
} else {
|
} else {
|
||||||
int lvl = chan_to_level(target);
|
int lvl = chan_to_level(target);
|
||||||
wprintf(lvl, "<%s> %s\n", sender, text);
|
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);
|
translate_async(text, lvl, translate_public ? target : NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user