34 #include "fileutils.h"
102 enum core_nexus_state
105 CORE_NEXUS_ESTABLISHED
112 CORE_CMD_GET_DISTRIB_PATS,
113 CORE_CMD_GET_SUBSCRIPTIONS,
114 CORE_CMD_RESET_GROUPSTATES,
115 CORE_CMD_GET_GROUPLIST,
116 CORE_CMD_GET_GROUPLABELS,
117 CORE_CMD_GET_GROUPINFO,
119 CORE_CMD_GET_OVERVIEW,
120 CORE_CMD_GET_ARTICLE_BY_MID,
121 CORE_CMD_GET_ARTICLE,
122 CORE_CMD_GET_ARTICLE_HEADER,
123 CORE_CMD_GET_ARTICLE_BODY,
124 CORE_CMD_POST_ARTICLE,
128 enum core_header_type
167 struct core_headerfield
169 enum core_header_id id;
170 enum core_header_type type;
176 enum core_nexus_state nntp_state;
177 const char* nntp_server;
179 const char* nntp_current_group;
194 #define MAIN_ERR_PREFIX "CORE: "
201 #define CORE_NEXUS_RETRIES 1U
207 #define CORE_HEADER_LINE_LENGTH (size_t) 1024
214 #define CORE_CFLAG_COMMENT 0x01U
215 #define CORE_CFLAG_QSTRING 0x02U
216 #define CORE_CFLAG_EWORD 0x04U
223 #define CORE_CL_SECRET_FILE ".cancelsecret"
235 #define CORE_UAGENT_RAW 0
244 static posix_pthread_t pt;
245 static int pt_valid = 0;
246 static posix_pthread_t ui_pt;
247 static posix_pthread_mutex_t pt_mutex = POSIX_PTHREAD_MUTEX_INITIALIZER;
248 static posix_pthread_cond_t pt_cond = POSIX_PTHREAD_COND_INITIALIZER;
250 static struct core_nexus* n = NULL;
251 static enum core_command command = CORE_CMD_INVALID;
268 static int check_iqscf(
const char* s,
const char* p,
unsigned int flags)
278 unsigned int cmt = 0;
283 if(!iew && lweq &&
'?' == s[i]) { iew = 1; }
287 if(lwbs) { escape = 1; }
else { escape = 0; }
289 if(0x5C == s[i] && !escape) { lwbs = 1; }
else { lwbs = 0; }
291 if(!iew && !iqs &&
'(' == s[i])
295 if(POSIX_UINT_MAX == cmt)
298 PRINT_ERROR(
"Header parser: Too many nested comments");
304 if(!iew && !cmt &&
'"' == s[i])
308 if(!iqs) { iqs = 1; }
else { iqs = 2; }
314 if(CORE_CFLAG_COMMENT & flags && cmt)
316 res |= (int) CORE_CFLAG_COMMENT;
318 if(CORE_CFLAG_QSTRING & flags && iqs)
320 res |= (int) CORE_CFLAG_QSTRING;
322 if(CORE_CFLAG_EWORD & flags && iew)
324 res |= (int) CORE_CFLAG_EWORD;
333 if(CORE_CFLAG_EWORD & flags) { printf(
"W"); }
334 else { printf(
" "); }
335 if(CORE_CFLAG_QSTRING & flags) { printf(
"S"); }
336 else { printf(
" "); }
337 if(CORE_CFLAG_COMMENT & flags) { printf(
"C"); }
338 else { printf(
" "); }
344 if(escape) { printf(
"E"); }
else
346 if(iqs) { printf(
"S"); }
349 if(9 >= cmt) { printf(
"%u", cmt); }
else { printf(
"0"); }
351 else { printf(
" "); }
354 if(!iew && !iqs &&
')' == s[i])
362 PRINT_ERROR(
"Header parser: Syntax error in comment");
367 if(!iew && !cmt &&
'"' == s[i])
369 if(!escape && 1 < iqs) { iqs = !iqs; }
372 if(iew && lwqm &&
'=' == s[i]) { iew = 0; }
373 if(
'=' == s[i]) { lweq = 1; }
else { lweq = 0; }
374 if(
'?' == s[i]) { lwqm = 1; }
else { lwqm = 0; }
380 printf(
"^ (res: %d)\n", res);
398 static int check_ic(
const char* s,
const char* p)
400 return(check_iqscf(s, p, CORE_CFLAG_COMMENT));
415 static int check_iqsc(
const char* s,
const char* p)
417 return(check_iqscf(s, p, CORE_CFLAG_QSTRING | CORE_CFLAG_COMMENT));
453 static char* convert_from_rfc850_to_rfc5536(
char* from)
456 size_t len = strlen(from);
467 name = strchr(from, (
int)
'(');
468 cp = strchr(from, (
int)
')');
469 if(cp) { comma = strchr(&cp[1], (
int)
','); }
470 if(NULL != name && cp > name)
473 if( (!comma && NULL == strchr(&name[1], (
int)
'(')
474 && NULL == strchr(from, (
int)
'<'))
476 (comma && (NULL == strchr(&name[1], (
int)
'(')
477 || strchr(&name[1], (
int)
'(') > comma)
478 && (NULL == strchr(from, (
int)
'<')
479 || strchr(from, (
int)
'<') > comma)) )
482 tmp = (
char*) posix_malloc(len * (
size_t) 2 + (size_t) 1);
485 i = (size_t) (name - from);
488 strncpy(tmp, from, len + (
size_t) 1); tmp[len] = 0;
489 if(comma) { tmp[(size_t) (comma - from)] = 0; }
496 if(NULL != strchr(addr, (
int)
'@'))
501 p = strchr(name, (
int)
')');
510 " in RFC 850 full name not supported");
514 if(NULL != strpbrk(name,
"()<>,:;"))
517 " full name in parenthesis");
530 if(NULL != strchr(name, (
int)
'"'))
539 == (
int) name[i - (
size_t) 1]) )
541 len = strlen(&name[i]);
542 memmove((
void*) (&name[i] + 1),
543 (
void*) &name[i], ++len);
551 p = strrchr(name, 0x5C);
552 if(NULL != p && !p[1])
554 if( (p != name && 0x5C != (
int) *(p - 1))
558 " quoted-pair in RFC 850"
559 " full name accepted/ignored");
570 res = (
char*) posix_malloc(len);
571 if (NULL == res) { res = from; }
577 posix_snprintf(res, len,
"<%s>", addr);
582 posix_snprintf(res, len,
"\"%s\" <%s>",
588 " first mailbox of mailbox-list"
593 printf(
"RFC 850 : %s\n", from);
594 printf(
"RFC 5536: %s\n", res);
596 posix_free((
void*) from);
607 posix_free((
void*) tmp);
663 static int header_parser(
struct core_headerfield** e,
const char* h)
665 const char* hfields[] =
667 "MESSAGE-ID",
"NEWSGROUPS",
"FROM",
668 "SUBJECT",
"DATE",
"SUPERSEDES",
669 "FOLLOWUP-TO",
"REPLY-TO",
"USER-AGENT",
670 "ORGANIZATION",
"REFERENCES",
"DISTRIBUTION",
671 "MIME-VERSION",
"CONTENT-TYPE",
"CONTENT-TRANSFER-ENCODING",
672 "CONTENT-DISPOSITION",
673 "X-NEWSREADER",
"X-MAILER",
"X-POSTING-AGENT",
677 enum core_header_id hfieldids[] =
679 CORE_HDR_MSGID, CORE_HDR_GROUPS, CORE_HDR_FROM,
680 CORE_HDR_SUBJECT, CORE_HDR_DATE, CORE_HDR_SUPERS,
681 CORE_HDR_FUP2, CORE_HDR_REPLY2, CORE_HDR_UAGENT,
682 CORE_HDR_ORG, CORE_HDR_REFS, CORE_HDR_DIST,
683 CORE_HDR_MIME, CORE_HDR_CT, CORE_HDR_CTE,
685 CORE_HDR_X_NEWSR, CORE_HDR_X_MAILER, CORE_HDR_X_PAGENT,
686 CORE_HDR_LINES, CORE_HDR_EOH
688 enum core_header_type hfieldtypes[] =
690 CORE_HT_STRUCT, CORE_HT_STRUCT, CORE_HT_STRUCT,
691 CORE_HT_UNSTRUCT, CORE_HT_STRUCT, CORE_HT_STRUCT,
692 CORE_HT_STRUCT, CORE_HT_STRUCT, CORE_HT_STRUCT,
693 CORE_HT_UNSTRUCT, CORE_HT_STRUCT, CORE_HT_STRUCT,
694 CORE_HT_STRUCT, CORE_HT_STRUCT, CORE_HT_STRUCT,
696 CORE_HT_STRUCT, CORE_HT_STRUCT, CORE_HT_STRUCT,
697 CORE_HT_STRUCT, CORE_HT_UNSTRUCT
714 struct core_headerfield hf;
718 struct core_headerfield* tmp;
722 *e = (
struct core_headerfield*)
723 posix_malloc(asize *
sizeof(
struct core_headerfield));
724 if (NULL == *e) { res = -1; }
729 buf = (
char*) posix_malloc(buflen);
730 if (NULL == buf) { res = -1; }
738 target = strchr(&h[i], (
int)
':');
739 if(target <= &h[i]) { resync = 1; }
742 len = (size_t) (target - &h[i]);
743 if(buflen <= len) { resync = 1; }
746 for(ii = 0; ii < len; ++ii)
748 buf[ii] = (char) toupper((
int) h[i + ii]);
760 while(NULL != hfields[ii])
762 if(!strcmp(hfields[ii], buf)) { used = 1;
break; }
773 hf.id = hfieldids[ii];
774 hf.type = hfieldtypes[ii];
782 if(CORE_HT_STRUCT == hf.type)
785 while(
' ' == h[++i]);
790 if(
' ' == h[++i]) { ++i; };
798 target = strchr(&h[i], 0x0D);
799 if(target <= &h[i]) { resync = 1;
break; }
803 len = (size_t) (target - &h[i]);
804 while(buflen <= ii + len)
806 p = (
char*) posix_realloc(buf, buflen *= (
size_t) 2);
807 if(NULL == p) { res = -1;
break; }
else { buf = p; }
809 if(-1 == res) {
break; }
811 memcpy((
void*) &buf[ii], (
void*) &h[i], len);
816 if((
const char) 0x0A != target[1])
818 PRINT_ERROR(
"Header parser: Invalid CR in field body");
823 if((
const char) 0x09 == target[2] || (
const char) 0x20 == target[2])
827 if(CORE_HT_STRUCT == hf.type)
835 while((
const char) 0x09 == h[i] || (
const char) 0x20 == h[i])
851 if(!buf[0]) { resync = 1; }
854 if(CORE_HDR_DIST == hf.id)
866 "Invalid characters replaced");
871 if(CORE_HT_STRUCT == hf.type)
877 case CORE_HDR_UAGENT:
883 case CORE_HDR_GROUPS:
885 case CORE_HDR_SUPERS:
892 case CORE_HDR_REPLY2:
900 buf = convert_from_rfc850_to_rfc5536(buf);
910 if(
'(' == buf[ii] && NULL == comment)
912 if(check_ic(buf, &buf[ii])) { comment = &buf[ii]; }
915 else if(NULL != comment &&
')' == buf[ii])
917 if(!check_ic(buf, &buf[ii + (
size_t) 1]))
920 len = strlen(&buf[++ii]);
921 memmove((
void*) comment, (
void*) &buf[ii], ++len);
922 ii = (size_t) (comment - buf);
936 if((
char) 0x09 == buf[ii]) { buf[ii] =
' '; }
937 if(ii &&
' ' == buf[ii])
939 if(
' ' == buf[ii - (
size_t) 1])
942 if( !( (
size_t) 2 <= ii
943 && 0x5C == (
int) buf[ii - (
size_t) 2]
944 && check_iqsc(buf, p) ) )
946 len = strlen(&buf[ii]);
947 memmove((
void*) p, (
void*) &buf[ii], ++len);
958 len = strlen(&buf[1]);
959 memmove((
void*) buf, (
void*) &buf[1], ++len);
962 if(CORE_HDR_CT == hf.id)
975 if(!inside_qs) { inside_qs = 1; }
979 if((
char) 0x5C != buf[ii - 1]) { inside_qs = 0; }
983 (
';' == buf[ii] ||
'=' == buf[ii] ||
'/' == buf[ii]))
985 if(
' ' == buf[ii - 1])
987 len = strlen(&buf[ii]);
988 memmove((
void*) &buf[ii - 1], (
void*) &buf[ii],
994 if(!inside_qs && (
'=' == buf[ii] ||
'/' == buf[ii]))
996 if(
' ' == buf[ii + 1])
998 len = strlen(&buf[ii + 2]);
999 memmove((
void*) &buf[ii + 1], (
void*) &buf[ii + 2],
1006 else if(CORE_HDR_CTE == hf.id)
1015 " Content-Transfer-Encoding field ignored");
1021 else if(CORE_HDR_FROM == hf.id || CORE_HDR_REPLY2 == hf.id)
1024 if(CORE_HDR_REPLY2 == hf.id)
1027 do { gstart = strchr(q, (
int)
':'); q = gstart + 1; }
1028 while(NULL != gstart && check_iqsc(buf, gstart));
1032 do { gend = strchr(q, (
int)
';'); q = gend + 1; }
1033 while(NULL != gend && check_iqsc(buf, gend));
1038 do { p = strchr(q, (
int)
','); q = p + 1; }
1039 while(NULL != p && check_iqsc(buf, p));
1040 if(NULL == p || p > gstart)
1044 " address of address-list processed");
1046 while(++gstart < gend)
1049 if(
' ' != *gstart && 0x09 != (
int) *gstart)
1054 len = (size_t) (gend - gstart);
1055 memmove((
void*) buf, (
void*) gstart, ++len);
1062 do { p = strchr(q, (
int)
','); q = p + 1; }
1063 while(NULL != p && check_iqsc(buf, p));
1066 PRINT_ERROR(
"Header parser: Only first mailbox of"
1067 " mailbox-list processed");
1071 p = strrchr(buf, (
int)
'<');
if(NULL == p) { p = buf; }
1075 if(&buf[ii] < p) { ++ii;
continue; }
1076 if(ii &&
' ' == buf[ii])
1079 if(
'<' == buf[ii - (
size_t) 1]
1080 ||
'@' == buf[ii - (
size_t) 1]
1081 ||
'>' == buf[ii + (
size_t) 1]
1082 ||
'@' == buf[ii + (
size_t) 1] )
1085 len = strlen(&buf[++ii]);
1086 memmove((
void*) p, (
void*) &buf[ii], ++len);
1093 #if !CORE_UAGENT_RAW
1095 else if(CORE_HDR_UAGENT == hf.id)
1101 if(ii &&
' ' == buf[ii])
1104 if(
'/' == buf[ii - (
size_t) 1]
1105 ||
'/' == buf[ii + (
size_t) 1] )
1108 len = strlen(&buf[++ii]);
1109 memmove((
void*) p, (
void*) &buf[ii], ++len);
1118 if(CORE_HDR_UAGENT != hf.id)
1127 if(
'"' == buf[ii]) { qstring = !qstring; skip = 1; }
1128 if(qstring && (
char) 0x5C == buf[ii]) { skip = 2; }
1132 len = strlen(&buf[++ii]);
1133 memmove((
void*) p, (
void*) &buf[ii], ++len);
1135 if(1 == skip) { --ii; }
1153 if(ai >= asize - (
size_t) 2)
1155 tmp = (
struct core_headerfield*)
1156 posix_realloc(*e, (asize *= (
size_t) 2)
1157 *
sizeof(
struct core_headerfield));
1158 if (NULL == tmp) { res = -1;
break; }
else { *e = tmp; }
1160 (*e)[ai].id = hf.id;
1161 (*e)[ai++].content = hf.content;
1164 buf = (
char*) posix_malloc(buflen);
1165 if (NULL == buf) { res = -1;
break; }
1172 target = strchr(&h[i], 0x0D);
1175 PRINT_ERROR(
"Header parser: Body separator missing");
1179 else { i += (size_t) (++target - &h[i]);}
1181 if((
const char) 0x0A == h[i]) { ++i; }
1183 if((
const char) 0x0D == h[i])
1185 if((
const char) 0x0A == h[i + 1])
1194 while(h[i] && (
' ' == h[i] || (
const char) 0x09 == h[i]));
1197 if(*e) { (*e)[ai].id = CORE_HDR_EOH; }
1200 posix_free((
void*) buf);
1206 while(CORE_HDR_EOH != (*e)[ai].
id)
1208 posix_free((
void*) (*e)[ai++].content);
1210 posix_free((
void*) *e);
1220 for(i = 0; i < 80; ++i) { printf(
"-"); } printf(
"\n");
1222 while(CORE_HDR_EOH != (*e)[ai].
id)
1227 if(hfieldids[i] == (*e)[ai].
id) {
break; }
1229 while(hfieldids[i++]);
1230 printf(
"%s: %s\n", hfields[i], (*e)[ai].content);
1233 for(i = 0; i < 80; ++i) { printf(
"-"); } printf(
"\n");
1251 static const char** extract_groups(
const char* body)
1253 const char** res = NULL;
1269 if(!body[i] ||
',' == body[i] ||
' ' == body[i]
1270 || (
const char) 0x09 == body[i])
1276 if (ne < ns) {
continue; }
1277 else { len = ne - ns; }
1278 group = (
char*) posix_malloc(len + (
size_t) 1);
1279 if(NULL == group) { err = 1;
break; }
1280 memcpy(group, &body[ns], len);
1284 if(POSIX_SIZE_MAX == asize) { err = 1;
break; }
1285 len = (asize + (size_t) 1) *
sizeof(
const char*);
1290 if(!bsize) { bsize =
sizeof(
const char*); }
1291 p = posix_realloc((
void*) res, bsize *= (
size_t) 2);
1292 if(NULL == p) { err = 1;
break; }
1295 res[asize - (size_t) 1] = (
const char*) group;
1296 res[asize++] = NULL;
1301 else {
if(!p_flag) { ns = i; p_flag = 1; } }
1308 posix_free((
void*) group);
1311 for(i = 0; i < asize; ++i) { posix_free((
void*) res[i]); }
1312 posix_free((
void*) res);
1332 static const char** extract_refs(
const char* body)
1334 const char** res = NULL;
1356 if(!body[i] ||
' ' == body[i] ||
'<' == body[i])
1365 "Invalid index in References (Bug)");
1371 if((
size_t) 2 > len || (
size_t) 250 < len)
1374 "Invalid length of MID in References");
1377 if(
'>' != body[ne - (
size_t) 1]) {
continue; }
1380 if(cfws_warn &&
'<' == body[i])
1382 PRINT_ERROR(
"Header parser: CFWS missing in References");
1385 msgid = (
char*) posix_malloc(len + (
size_t) 1);
1386 if(NULL == msgid) { err = 1;
break; }
1387 memcpy(msgid, &body[ns], len);
1391 if(POSIX_SIZE_MAX == asize) {
break; }
1392 len = (asize + (size_t) 1) *
sizeof(
const char*);
1397 if(!bsize) { bsize =
sizeof(
const char*); }
1398 p = posix_realloc((
void*) res, bsize *= (
size_t) 2);
1399 if(NULL == p) {
break; }
1402 res[asize - (size_t) 1] = (
const char*) msgid;
1403 res[asize++] = NULL;
1409 if(
'<' == body[i]) { ns = i; p_flag = 1; }
1417 for(i = 0; i < asize; ++i) { posix_free((
void*) res[i]); }
1418 posix_free((
void*) res);
1436 posix_free((
void*) (*ahp)->msgid);
1437 if(NULL != (*ahp)->groups)
1440 while(NULL != (*ahp)->groups[i])
1442 posix_free((
void*) (*ahp)->groups[i++]);
1444 posix_free((
void*) (*ahp)->groups);
1446 posix_free((
void*) (*ahp)->from);
1447 posix_free((
void*) (*ahp)->subject);
1449 posix_free((
void*) (*ahp)->supers);
1450 posix_free((
void*) (*ahp)->fup2);
1451 posix_free((
void*) (*ahp)->reply2);
1452 posix_free((
void*) (*ahp)->uagent);
1453 posix_free((
void*) (*ahp)->org);
1454 if(NULL != (*ahp)->refs)
1457 while(NULL != (*ahp)->refs[i])
1459 posix_free((
void*) (*ahp)->refs[i++]);
1461 posix_free((
void*) (*ahp)->refs);
1463 posix_free((
void*) (*ahp)->dist);
1464 posix_free((
void*) (*ahp)->mime_v);
1465 posix_free((
void*) (*ahp)->mime_ct);
1466 posix_free((
void*) (*ahp)->mime_cte);
1467 posix_free((
void*) (*ahp)->mime_cd);
1468 posix_free((
void*) (*ahp)->x_newsr);
1469 posix_free((
void*) (*ahp)->x_mailer);
1470 posix_free((
void*) (*ahp)->x_pagent);
1474 posix_free((
void*) *ahp);
1488 #define CORE_GET_EMPTY_STRING(p) \
1490 p = (char*) posix_malloc(1); \
1491 if(NULL == p) { res = -1; } \
1492 else { ((char*) p)[0] = 0; } \
1495 #define CORE_GET_ERROR_STRING(p) \
1497 p = (char*) posix_malloc(34); \
1498 if(NULL == p) { res = -1; } \
1499 else { strcpy((char*) p, "[Missing or invalid header field]"); } \
1505 struct core_headerfield* e = NULL;
1511 res = header_parser(&e, h);
1517 if(NULL == *ahp) { res = -1; }
1522 (*ahp)->msgid = NULL;
1523 (*ahp)->groups = NULL;
1524 (*ahp)->from = NULL;
1525 (*ahp)->subject = NULL;
1528 (*ahp)->supers = NULL;
1529 (*ahp)->fup2 = NULL;
1530 (*ahp)->reply2 = NULL;
1531 (*ahp)->uagent = NULL;
1533 (*ahp)->refs = NULL;
1534 (*ahp)->dist = NULL;
1535 (*ahp)->mime_v = NULL;
1536 (*ahp)->mime_ct = NULL;
1537 (*ahp)->mime_cte = NULL;
1538 (*ahp)->mime_cd = NULL;
1539 (*ahp)->x_newsr = NULL;
1540 (*ahp)->x_mailer = NULL;
1541 (*ahp)->x_pagent = NULL;
1546 while(CORE_HDR_EOH != e[i].
id)
1550 case CORE_HDR_MSGID:
1554 (*ahp)->msgid = e[i].content;
1555 e[i].content = NULL;
1559 case CORE_HDR_GROUPS:
1563 (*ahp)->groups = extract_groups(e[i].content);
1573 if(!rv) { mime = 1; }
1574 else { mime_s = e[i].content; e[i].content = NULL; }
1575 (*ahp)->from = mime_s;
1579 case CORE_HDR_SUBJECT:
1581 if(!(*ahp)->subject)
1584 if(!rv) { mime = 1; }
1585 else { mime_s = e[i].content; e[i].content = NULL; }
1586 (*ahp)->subject = mime_s;
1598 case CORE_HDR_SUPERS:
1602 (*ahp)->supers = e[i].content;
1603 e[i].content = NULL;
1611 (*ahp)->fup2 = e[i].content;
1612 e[i].content = NULL;
1616 case CORE_HDR_REPLY2:
1621 if(!rv) { mime = 1; }
1622 else { mime_s = e[i].content; e[i].content = NULL; }
1623 (*ahp)->reply2 = mime_s;
1627 case CORE_HDR_UAGENT:
1632 if(!rv) { mime = 1; }
1633 else { mime_s = e[i].content; e[i].content = NULL; }
1634 (*ahp)->uagent = mime_s;
1643 if(!rv) { mime = 1; }
1644 else { mime_s = e[i].content; e[i].content = NULL; }
1645 (*ahp)->org = mime_s;
1653 (*ahp)->refs = extract_refs(e[i].content);
1662 (*ahp)->dist = e[i].content;
1663 e[i].content = NULL;
1671 (*ahp)->mime_v = e[i].content;
1672 e[i].content = NULL;
1678 if(!(*ahp)->mime_ct)
1681 if(!rv) { mime = 1; }
1682 else { mime_s = e[i].content; e[i].content = NULL; }
1683 (*ahp)->mime_ct = mime_s;
1690 if(!(*ahp)->mime_cte)
1692 (*ahp)->mime_cte = e[i].content;
1693 e[i].content = NULL;
1699 if(!(*ahp)->mime_cd)
1702 if(rv) { mime_s = e[i].content; e[i].content = NULL; }
1703 (*ahp)->mime_cd = mime_s;
1707 case CORE_HDR_X_NEWSR:
1709 if(!(*ahp)->x_newsr)
1712 if(!rv) { mime = 1; }
1713 else { mime_s = e[i].content; e[i].content = NULL; }
1714 (*ahp)->x_newsr = mime_s;
1718 case CORE_HDR_X_MAILER:
1720 if(!(*ahp)->x_mailer)
1723 if(!rv) { mime = 1; }
1724 else { mime_s = e[i].content; e[i].content = NULL; }
1725 (*ahp)->x_mailer = mime_s;
1729 case CORE_HDR_X_PAGENT:
1731 if(!(*ahp)->x_pagent)
1734 if(!rv) { mime = 1; }
1735 else { mime_s = e[i].content; e[i].content = NULL; }
1736 (*ahp)->x_pagent = mime_s;
1740 case CORE_HDR_LINES:
1760 while(CORE_HDR_EOH != e[i].
id)
1762 posix_free((
void*) e[i++].content);
1764 posix_free((
void*) e);
1769 if(NULL == (*ahp)->msgid) { CORE_GET_EMPTY_STRING((*ahp)->msgid); }
1770 if(NULL == (*ahp)->groups)
1772 (*ahp)->groups = (
const char**)
1773 posix_malloc(
sizeof(
const char*) * (size_t) 2);
1774 if(NULL != (*ahp)->groups)
1776 CORE_GET_EMPTY_STRING((*ahp)->groups[0]);
1777 (*ahp)->groups[1] = NULL;
1780 if(NULL == (*ahp)->from) { CORE_GET_ERROR_STRING((*ahp)->from); }
1781 if(NULL == (*ahp)->subject)
1783 CORE_GET_ERROR_STRING((*ahp)->subject);
1788 if(res) { header_object_destructor(ahp); }
1797 "MIME-Version field missing, but MIME is used");
1816 if(NULL == *he) { res = -1; }
1821 (*he)->flags =
flags;
1822 (*he)->header = NULL;
1823 (*he)->parent = NULL;
1824 (*he)->children = 0;
1825 (*he)->child = NULL;
1840 header_object_destructor(&(*he)->header);
1842 posix_free((
void*) (*he)->child);
1844 posix_free((
void*) *he);
1864 if(!root) { res = -1; }
1872 while((*current)->children)
1875 current = &(*current)->
child[(*current)->children - (size_t) 1];
1878 hierarchy_element_destructor(current);
1881 res = hierarchy_element_constructor(root, 0, 0);
1899 for(i = 0; i < root->
children; ++i)
1903 res = root->
child[i];
1909 tmp = hierarchy_find_article(msgid, root->
child[i]);
1910 if(tmp != root->
child[i])
1931 if(a_date < b_date) { res = -1; }
1932 if(a_date > b_date) { res = 1; }
1937 if(a_date < b_date) { res = 1; }
1938 if(a_date > b_date) { res = -1; }
1955 const char supers_subject[] =
"[Superseded]";
1962 if(NULL == *root) { res = -1; }
1967 res = hierarchy_element_constructor(&he_new, num,
flags);
1976 fprintf(stderr,
"%s: %sAdd article %s to hierarchy ...\n",
1980 res = header_object_constructor(&he_new->
header,
header);
1983 if(0 > res) { posix_free((
void*) he_new); }
1992 he_super = hierarchy_find_article(he_new->
header->
supers, *root);
1993 if(he_super != *root)
1996 size = strlen(supers_subject);
1997 tmp = (
char*) posix_realloc((
void*) he_super->
header->
subject,
2001 PRINT_ERROR(
"Memory allocation for subject field failed");
2005 strcpy(tmp, supers_subject);
2019 while(NULL != he_new->
header->
refs[i]) { ++i; };
2022 he_parent = hierarchy_find_article(he_new->
header->
refs[--i],
2024 if(he_parent != *root) {
break; }
2028 size = (he_parent->
children + (size_t) 1)
2031 posix_realloc(he_parent->
child, size);
2032 if(NULL == he_tmp) { res = -1; }
2034 if(res) { hierarchy_element_destructor(&he_new); }
2037 he_parent->
child = he_tmp;
2038 he_new->
parent = he_parent;
2043 (int (*)(
const void*,
const void*)) hierarchy_sort_children);
2062 for(i = 0; i < root->
children; ++i)
2066 res = root->
child[i];
2072 tmp = hierarchy_find_element(num, root->
child[i]);
2093 if(NULL == *root) { res = -1; }
2098 he = hierarchy_find_element(num, *root);
2099 if(NULL == he) { res = -1; }
2103 if(!res) { res = header_object_constructor(&hdr, header); }
2108 header_object_destructor(&he->
header);
2119 static int nexus_constructor(
struct core_nexus** nexus,
const char* server)
2126 s = (
char*) posix_malloc(strlen(server) + (size_t) 1);
2130 *nexus = (
struct core_nexus*) posix_malloc(
sizeof(
struct core_nexus));
2131 if(NULL == *nexus) { posix_free((
void*) s); }
2134 (*nexus)->nntp_state = CORE_NEXUS_CLOSED;
2135 (*nexus)->nntp_server = s;
2136 (*nexus)->nntp_handle = -1;
2137 (*nexus)->nntp_current_group = NULL;
2150 static void nexus_destructor(
struct core_nexus** nexus)
2154 if(NULL != (*nexus)->nntp_server)
2156 posix_free((
void*) (*nexus)->nntp_server);
2158 if(NULL != (*nexus)->nntp_current_group)
2160 posix_free((
void*) (*nexus)->nntp_current_group);
2162 posix_free((
void*) *nexus);
2171 static int nexus_open(
struct core_nexus** nexus)
2185 printf(
"%s: %sProtocol logfile: %s\n",
2195 posix_free((
void*) logpathname);
2212 res =
nntp_open(&(*nexus)->nntp_handle, (*nexus)->nntp_server,
2213 service, logpathname, enc, auth);
2220 PRINT_ERROR(
"Authentication with empty password rejected");
2225 res =
nntp_open(&(*nexus)->nntp_handle, (*nexus)->nntp_server,
2226 service, logpathname, enc, auth,
2233 PRINT_ERROR(
"Authentication algorithm not supported");
2238 if (0 > res) { (*nexus)->nntp_state = CORE_NEXUS_CLOSED; }
2239 else { (*nexus)->nntp_state = CORE_NEXUS_ESTABLISHED; }
2242 posix_free((
void*) logpathname);
2255 static void nexus_close(
struct core_nexus** nexus)
2260 if(-1 != (*nexus)->nntp_handle)
2265 nexus_destructor(nexus);
2275 static int nexus_handler(
struct core_nexus** nexus)
2280 if(NULL == *nexus) { res = -1; }
2281 else if(CORE_NEXUS_ESTABLISHED != (*nexus)->nntp_state) { res = -1; }
2285 res = nexus_open(nexus);
2289 if(NULL != (*nexus)->nntp_current_group)
2291 nntp_set_group((*nexus)->nntp_handle, (*nexus)->nntp_current_group,
2311 static int check_connection(
int r)
2321 n->nntp_state = CORE_NEXUS_CLOSED;
2324 else if(-3 == r) { res = -1; }
2333 static void get_motd(
void)
2342 res = nexus_handler(&n);
2353 if(check_connection(res)) {
break; }
2355 while(res && retries--);
2363 static void get_distrib_pats(
void)
2367 const char* d_pats = NULL;
2372 res = nexus_handler(&n);
2383 if(check_connection(res)) {
break; }
2385 while(res && retries--);
2393 static void get_subscriptions(
void)
2402 res = nexus_handler(&n);
2413 if(check_connection(res)) {
break; }
2415 while(res && retries--);
2423 static void reset_group_states(
void)
2431 if(!res) { res = rv; }
2440 static void get_group_list(
void)
2449 res = nexus_handler(&n);
2459 if(check_connection(res)) {
break; }
2461 while(0 > res && retries--);
2469 static void get_group_labels(
void)
2478 res = nexus_handler(&n);
2488 if(check_connection(res)) {
break; }
2490 while(0 > res && retries--);
2498 static void get_groupinfo(
void)
2522 gl = (
const char**) posix_malloc(gc *
sizeof(
const char*));
2525 for(i = 0; i < gc; ++i) { gl[i] = (*gs)[i].name; }
2527 posix_free((
void*) gl);
2531 res = nexus_handler(&n);
2537 if(NULL == garray) { res = -1;
break; }
2539 for(i = 0; i < gc; ++i)
2546 if(-2 == res) {
break; }
2556 if(NULL == gd) {
break; }
2559 memcpy((
void*) &garray[i], (
void*) gd,
2562 memcpy((
void*) &garray[i].
name, (
void*) &(*gs)[i].
name,
2563 sizeof(
const char*));
2564 posix_free((
void*) gd);
2569 posix_free((
void*) garray);
2572 else {
data.
data = (
void*) garray; }
2573 if(check_connection(res)) {
break; }
2575 while(0 > res && retries--);
2584 static void set_group(
void)
2595 res = nexus_handler(&n);
2607 gn = (
char*) posix_malloc(++len);
2608 if(NULL == gn) { n->nntp_current_group = NULL; }
2612 if(NULL != n->nntp_current_group)
2614 posix_free((
void*) n->nntp_current_group);
2616 n->nntp_current_group = (
const char*) gn;
2629 if(check_connection(res)) {
break; }
2631 while(res && retries--);
2639 static void get_overview(
void)
2644 char* overview = NULL;
2649 res = nexus_handler(&n);
2661 if(check_connection(res)) {
break; }
2663 while(res && retries--);
2671 static void get_article_by_mid(
void)
2675 char* article = NULL;
2680 res = nexus_handler(&n);
2692 if(check_connection(res)) {
break; }
2694 while(res && retries--);
2702 static void get_article(
void)
2706 char* article = NULL;
2711 res = nexus_handler(&n);
2723 if(check_connection(res)) {
break; }
2725 while(res && retries--);
2733 static void get_article_header(
void)
2737 char* header = NULL;
2742 res =
db_read(n->nntp_current_group, *anum, &header, &len);
2754 res = nexus_handler(&n);
2768 db_add(n->nntp_current_group, *anum, header, strlen(header));
2784 if(check_connection(res)) {
break; }
2786 while(res && retries--);
2795 static void get_article_body(
void)
2804 res = nexus_handler(&n);
2817 if(check_connection(res)) {
break; }
2819 while(res && retries--);
2827 static void post_article(
void)
2834 res = nexus_handler(&n);
2839 if(check_connection(res)) {
break; }
2841 while(res && retries--);
2853 static void cleanup_handler(
void* arg)
2867 static void* core_main(
void* arg)
2872 posix_pthread_cleanup_push(cleanup_handler, NULL);
2879 rv = posix_pthread_cond_wait(&pt_cond, &pt_mutex);
2889 case CORE_CMD_GET_MOTD:
2894 case CORE_CMD_GET_DISTRIB_PATS:
2899 case CORE_CMD_GET_SUBSCRIPTIONS:
2901 get_subscriptions();
2904 case CORE_CMD_RESET_GROUPSTATES:
2906 reset_group_states();
2909 case CORE_CMD_GET_GROUPLIST:
2914 case CORE_CMD_GET_GROUPLABELS:
2919 case CORE_CMD_GET_GROUPINFO:
2924 case CORE_CMD_SET_GROUP:
2929 case CORE_CMD_GET_OVERVIEW:
2934 case CORE_CMD_GET_ARTICLE_BY_MID:
2936 get_article_by_mid();
2939 case CORE_CMD_GET_ARTICLE:
2944 case CORE_CMD_GET_ARTICLE_HEADER:
2946 get_article_header();
2949 case CORE_CMD_GET_ARTICLE_BODY:
2954 case CORE_CMD_POST_ARTICLE:
2960 case CORE_TERMINATE_NEXUS:
2978 command = CORE_CMD_INVALID;
2986 posix_pthread_cleanup_pop(1);
2999 static int commands_in_queue(
unsigned int checks,
unsigned int to)
3006 for(i = 0; i < checks; ++i)
3011 rv = posix_pthread_mutex_trylock(&pt_mutex);
3014 if(CORE_CMD_INVALID == command)
3034 static void core_distrib_pats_destructor(
struct distrib_pats*** pats)
3038 if(NULL != pats && NULL != *pats)
3040 while(NULL != (*pats)[i])
3042 posix_free((
void*) (*pats)[i]->wildmat);
3043 posix_free((
void*) (*pats)[i]->dist);
3044 posix_free((
void*) (*pats)[i++]);
3046 posix_free((
void*) *pats);
3074 static int core_distrib_pats_constructor(
struct distrib_pats*** pats,
3078 size_t sosp =
sizeof(
struct distrib_pats*);
3085 unsigned long int weight;
3086 char* wildmat = NULL;
3088 struct distrib_pats* element = NULL;
3089 struct distrib_pats**
object = NULL;
3092 struct distrib_pats* tmp2;
3093 struct distrib_pats** tmp3;
3100 tmp3 = (
struct distrib_pats**) posix_malloc(sosp);
3114 p = strchr(&raw[i], 0x0A);
3118 if(NULL !=
object) { res = 0; }
3123 line_len = (size_t) (p - &raw[i]);
3126 tmp = (
char*) posix_realloc(line, line_len + (
size_t) 1);
3127 if(NULL == tmp) {
break; }
3131 strncpy(line, &raw[i], line_len);
3134 tmp = (
char*) posix_realloc(wildmat, line_len + (
size_t) 1);
3135 if(NULL == tmp) {
break; }
else { wildmat = tmp; }
3136 tmp = (
char*) posix_realloc(dist, line_len + (
size_t) 1);
3137 if(NULL == tmp) {
break; }
else { dist = tmp; }
3138 rv = sscanf(line,
"%lu:%[^][\\:\r\n]:%s", &weight, wildmat, dist);
3141 PRINT_ERROR(
"Invalid distribution pattern ignored");
3146 tmp2 = (
struct distrib_pats*)
3147 posix_malloc(
sizeof(
struct distrib_pats));
3151 element->weight = weight;
3152 element->wildmat = wildmat; wildmat = NULL;
3153 element->dist = dist; dist = NULL;
3155 tmp3 = (
struct distrib_pats**)
3156 posix_realloc(
object, ++objects * sosp);
3159 posix_free((
void*) element->wildmat);
3160 posix_free((
void*) element->dist);
3161 posix_free((
void*) element);
3167 object[objects - 2] = element;
3168 object[objects - 1] = NULL;
3179 if(res && !raw[i] && NULL !=
object) { res = 0; }
3182 posix_free((
void*) line);
3183 posix_free((
void*) wildmat);
3184 posix_free((
void*) dist);
3185 posix_free((
void*) raw);
3188 if(res) { core_distrib_pats_destructor(&
object); }
3189 else { *pats = object; }
3214 static int core_check_line_length(
const char* article)
3224 p = strchr(&article[i], 0x0D);
3225 if(NULL == p) {
break; }
3226 len = p - &article[i];
3228 if(0x0A != (
int) article[i + len + (
size_t) 1])
3230 PRINT_ERROR(
"Invalid CR control character (not part of line break)");
3236 PRINT_ERROR(
"Article contains lines with more than 998 octets");
3240 i += len + (size_t) 1;
3241 if(article[i]) { ++i; }
3247 p = strchr(&article[i], 0x00);
3255 len = p - &article[i];
3258 PRINT_ERROR(
"Article contains lines with more than 998 octets");
3286 return(extract_groups(body));
3324 if(CORE_CMD_INVALID == command)
3328 command = CORE_CMD_GET_GROUPLIST;
3332 rv = posix_pthread_cond_signal(&pt_cond);
3333 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
3383 if(CORE_CMD_INVALID == command)
3387 command = CORE_CMD_GET_GROUPLABELS;
3391 rv = posix_pthread_cond_signal(&pt_cond);
3392 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
3443 PRINT_ERROR(
"Subscription rejected for invalid group name");
3473 if(!*num || *index > *num - (
size_t) 1) { res = -1; }
3476 posix_free((
void*) (*list)[*index].
name);
3478 if(*index < *num - (
size_t) 1)
3480 memmove((
void*) &(*list)[*index],
3481 (
void*) &(*list)[*index + (
size_t) 1],
3485 if(*index) { --*index; }
3519 if(CORE_CMD_INVALID == command)
3523 command = CORE_CMD_RESET_GROUPSTATES;
3527 rv = posix_pthread_cond_signal(&pt_cond);
3528 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
3586 size_t num_old = *num;
3588 size_t index_old = *index;
3601 if(num && num_old && NULL != *list && NULL != list_old)
3604 for(i = 0; i < *num; ++i)
3607 for(ii = 0; ii < num_old; ++ii)
3609 if(!strcmp((*list)[i].
name, list_old[ii].
name))
3611 (*list)[i].last_viewed = list_old[ii].
last_viewed;
3615 if(!strcmp((*list)[i].
name, list_old[index_old].
name))
3687 unsigned int cookie)
3694 if(CORE_CMD_INVALID == command)
3700 command = CORE_CMD_GET_GROUPINFO;
3704 rv = posix_pthread_cond_signal(&pt_cond);
3705 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
3734 posix_free((
void*) *list);
3770 if(CORE_CMD_INVALID == command)
3775 command = CORE_CMD_SET_GROUP;
3779 rv = posix_pthread_cond_signal(&pt_cond);
3780 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
3833 PRINT_ERROR(
"Server doesn't provide message of the day");
3838 if(CORE_CMD_INVALID == command)
3843 command = CORE_CMD_GET_MOTD;
3847 rv = posix_pthread_cond_signal(&pt_cond);
3848 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
3889 struct distrib_pats** pats = NULL;
3890 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
3909 PRINT_ERROR(
"Empty group list for distribution suggestions");
3913 PRINT_ERROR(
"Distribution suggestions disabled by configuration");
3921 posix_snprintf(x, (
size_t) 1024,
"%s",
3922 "3:de.alt.test:de\r\n"
3931 PRINT_ERROR(
"Server doesn't provide distribution suggestions");
3935 if(!res) { res = core_distrib_pats_constructor(&pats,
data); }
3942 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
3944 while(NULL != groups[i])
3955 PRINT_ERROR(
"Unicode groupname ignored (not supported yet)");
3962 while(NULL != pats[ii])
3973 PRINT_ERROR(
"Unicode wildmat ignored (not supported yet)");
3984 for(iii = num; iii; --iii)
3987 rv = posix_regcomp(&ere, wma[iii - 1].ere,
3988 POSIX_REG_EXTENDED | POSIX_REG_NOSUB);
3991 PRINT_ERROR(
"Compiling regular expression failed");
3996 rv = posix_regexec(&ere, groups[i], 0, NULL, 0);
3997 posix_regfree(&ere);
4001 if(wma[iii - 1].negate)
4007 if(weight <= pats[ii]->weight)
4010 weight = pats[ii]->weight;
4026 len = strlen(pats[match]->dist);
4029 buf = (
char*) posix_malloc(++len);
4033 strcpy(buf, pats[match]->dist);
4040 p = (
char*) posix_realloc((
void*) buf, ++len + buf_len);
4046 strcat(buf, pats[match]->dist);
4055 PRINT_ERROR(
"Distribution pattern matching requires regular "
4056 "expression support");
4062 core_distrib_pats_destructor(&pats);
4066 if(!res) { printf(
"Suggested distribution: %s\n", *dist); }
4109 if(CORE_CMD_INVALID == command)
4114 command = CORE_CMD_GET_SUBSCRIPTIONS;
4118 rv = posix_pthread_cond_signal(&pt_cond);
4119 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
4178 if(CORE_CMD_INVALID == command)
4183 command = CORE_CMD_GET_OVERVIEW;
4187 rv = posix_pthread_cond_signal(&pt_cond);
4188 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
4242 if(CORE_CMD_INVALID == command)
4247 command = CORE_CMD_GET_ARTICLE_BY_MID;
4251 rv = posix_pthread_cond_signal(&pt_cond);
4252 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
4304 if(CORE_CMD_INVALID == command)
4309 command = CORE_CMD_GET_ARTICLE;
4313 rv = posix_pthread_cond_signal(&pt_cond);
4314 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
4366 if(CORE_CMD_INVALID == command)
4371 command = CORE_CMD_GET_ARTICLE_HEADER;
4375 rv = posix_pthread_cond_signal(&pt_cond);
4376 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
4428 if(CORE_CMD_INVALID == command)
4433 command = CORE_CMD_GET_ARTICLE_BODY;
4437 rv = posix_pthread_cond_signal(&pt_cond);
4438 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
4499 const char* a = NULL;
4500 const char* header = NULL;
4501 const char* body = NULL;
4506 const char hl_te[] =
"Content-Transfer-Encoding: 8bit\r\n";
4507 const char hl_ct[] =
"Content-Type: text/plain; charset=";
4508 const char hl_ct_ff[] =
"; format=fixed\r\n";
4509 const char* cs_iana =
"UTF-8";
4515 len = strlen(article);
4516 p = (
char*) posix_malloc(++len);
4519 PRINT_ERROR(
"Memory allocation for article failed");
4524 strncpy(p, article, len);
4534 PRINT_ERROR(
"Article encoding check/normalization failed");
4541 p = (
char*) posix_malloc(++len);
4544 PRINT_ERROR(
"Memory allocation for article failed");
4547 else { strncpy(p, a, len); }
4548 if(a != article) {
enc_free((
void*) a); }
4555 p = strstr(a,
"\r\n\r\n");
4558 PRINT_ERROR(
"Article to post contains no header separator");
4563 len = (size_t) (p - a) + (size_t) 2;
4564 q = (
char*) posix_malloc(++len);
4567 PRINT_ERROR(
"Memory allocation for article header failed");
4572 strncpy(q, a, --len); q[len] = 0;
4577 PRINT_ERROR(
"Article to post has invalid header encoding");
4587 len = strlen(&p[4]);
4588 q = (
char*) posix_malloc(++len);
4591 PRINT_ERROR(
"Memory allocation for article body failed");
4596 strncpy(q, &p[4], --len); q[len] = 0;
4610 p = (
char*) posix_malloc(++len);
4621 posix_free((
void*) body);
4633 len = strlen(header) + strlen(hl_te);
4634 len += strlen(hl_ct) + strlen(cs_iana) + strlen(hl_ct_ff);
4635 p = (
char*) posix_malloc(++len);
4638 PRINT_ERROR(
"Memory allocation for MIME header field failed");
4645 strcat(p, hl_ct); strcat(p, cs_iana); strcat(p, hl_ct_ff);
4646 posix_free((
void*) header);
4655 len += strlen(header);
4656 len += strlen(body);
4657 p = (
char*) posix_malloc(++len);
4660 PRINT_ERROR(
"Memory allocation for final article failed");
4668 posix_free((
void*) a);
4675 posix_free((
void*) header);
4676 posix_free((
void*) body);
4679 rv = core_check_line_length(a);
4680 if(rv) { res = -1; }
4690 if(res) { res = -1; }
4696 if(CORE_CMD_INVALID == command)
4702 command = CORE_CMD_POST_ARTICLE;
4705 rv = posix_pthread_cond_signal(&pt_cond);
4710 command = CORE_CMD_INVALID;
4724 if(0 >= res) { posix_free((
void*) a); }
4751 if(a >= cr->
first && a <= cr->
last) { res = 1;
break; }
4771 int before_current = 0;
4781 printf(
"\nGroup: %s\n", group->
name);
4784 printf(
" %lu-%lu\n", cr->
first, cr->
last);
4788 printf(
"Mark as read: %lu\n", a);
4791 if(NULL == cr) { new_range = 1; }
4797 if(a >= cr->
first && a <= cr->
last) {
break; }
4803 else { new_range = 1; before_current = 1; }
4809 if(NULL == cr->
next) { new_range = 1;
break; }
4810 else { cr = cr->
next; }
4819 if(NULL == cr) { group->
info = cr = nr; }
4826 memcpy((
void*) &tmp, (
void*) cr,
sizeof(
struct core_range));
4827 memcpy((
void*) cr, (
void*) nr,
sizeof(
struct core_range));
4828 memcpy((
void*) nr, (
void*) &tmp,
sizeof(
struct core_range));
4839 if(NULL != cr->
next)
4846 posix_free((
void*) nr);
4856 printf(
" %lu-%lu\n", cr->
first, cr->
last);
4885 printf(
"\nGroup: %s\n", group->
name);
4888 printf(
" %lu-%lu\n", cr->
first, cr->
last);
4892 printf(
"Mark as unread: %lu\n", a);
4907 if(NULL == lr) { group->
info = cr; }
4908 else { lr->
next = cr; }
4910 else if(a == cr->
first)
4915 else if(a == cr->
last)
4934 else { lr = cr; cr = cr->
next; }
4941 printf(
" %lu-%lu\n", cr->
first, cr->
last);
5058 if(NULL == hier) { hier = &h; }
5064 res = hierarchy_init(hier);
5069 if(NULL == *hier) { res = -1; }
5075 res = hierarchy_add(hier, anum, 0U, va_arg(ap,
const char*));
5081 va_arg(ap,
const char*));
5086 res = hierarchy_update(hier, anum, va_arg(ap,
const char*));
5118 const char* overview)
5120 static const char mime_v_field[] =
"MIME-Version: 1.0\r\n";
5121 static const char newsgroups_field[] =
"Newsgroups: ";
5123 static const char* field[] =
5125 "",
"Subject: ",
"From: ",
"Date: ",
"Message-ID: ",
"References: ",
5131 char* header = NULL;
5140 unsigned int f_max = 7;
5148 if(!rv && (
size_t) 7 < tmp && POSIX_UINT_MAX > tmp)
5155 header = (
char*) posix_malloc(hlen);
5157 len = strlen(overview);
5158 content = (
char*) posix_malloc(++len);
5160 while(NULL != header && NULL != content)
5163 strcpy(header, mime_v_field);
5164 hi =
sizeof(mime_v_field) - (
size_t) 1;
5168 rv = posix_snprintf(&header[hi], hlen - hi,
"%s%s\r\n",
5169 newsgroups_field, group->
name);
5172 if(hlen - hi > (
size_t) rv) { hi += (size_t) rv; }
5176 rv = sscanf(&overview[i],
"%s", content);
5186 for(f = 1; f_max >= f; ++f)
5189 p = strchr(&overview[i], 0x09);
5196 i += (size_t) (p - &overview[i]) + (size_t) 1;
5198 if(6U == f || (7U < f && f_max != f)) {
continue; }
5200 if(0x09 == (
int) (
unsigned char) overview[i]) {
continue; }
5201 rv = sscanf(&overview[i],
"%[^\t]", content);
5208 len = strlen(field[f]) + strlen(content) + (size_t) 3;
5209 while(hlen - hi < len)
5211 q = (
char*) posix_realloc(header, hlen *= (
size_t) 2);
5212 if(NULL == q) { error = 1;
break; }
5213 else { header = q; }
5218 rv = posix_snprintf(&header[hi], hlen - hi,
"%s%s\r\n",
5224 rv = posix_snprintf(&header[hi], hlen - hi,
"%s\r\n",
5229 if(hlen - hi <= (
size_t) rv)
5232 " parser detected (Bug)");
5245 printf(
"Pseudo-Header generated from overview:\n---\n%s---\n",
5250 if(0 > rv) { error = 1; }
5260 p = strchr(&overview[i], 0x0A);
5261 if(NULL == p) {
break; }
5262 i += (size_t) (p - &overview[i]) + (size_t) 1;
5269 if(NULL == header || NULL == content)
5271 PRINT_ERROR(
"Out of memory while processing header overview data");
5273 posix_free((
void*) header);
5274 posix_free((
void*) content);
5299 const char* res = NULL;
5307 for(i = 0; i < len; ++i)
5309 if(i && (
char) 0x0A == entity[i])
5311 if((
char) 0x0D == entity[i - (
size_t) 1])
5314 if((
size_t) 1 == i) { sob = ++i;
break; }
5315 else if((
size_t) 3 <= i)
5317 if((
char) 0x0A == entity[i - (
size_t) 2]
5318 && (
char) 0x0D == entity[i - (
size_t) 3])
5327 if((
size_t) 2 <= sob)
5331 h_len = sob - (size_t) 2;
5332 h = (
char*) posix_malloc(h_len + (
size_t) 1);
5336 strncpy(h, entity, h_len); h[h_len] = 0;
5344 rv = header_object_constructor(e_h, h);
5345 if(rv) { res = NULL; }
5347 posix_free((
void*) h);
5361 header_object_destructor(ehp);
5379 const char* buf = NULL;
5385 posix_free((
void*) buf);
5415 const char* name = CFG_NAME;
5416 char date[17] = { 0 };
5418 struct_posix_tm t_data;
5419 struct_posix_tm* t = NULL;
5426 t = posix_gmtime_r(&ts, &t_data);
5430 rv = posix_snprintf(date, (
size_t) 17,
"%04d%02d%02dT%02d%02d%02dZ",
5431 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
5432 t->tm_hour, t->tm_min, t->tm_sec);
5435 PRINT_ERROR(
"Created date and time string is invalid (bug)");
5439 len += strlen(path);
5441 len += strlen(name);
5443 len += strlen(date);
5444 buf = (
char*) posix_malloc(len);
5487 static const char* months[12] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
5488 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec" };
5489 static const char* weekday[7] = {
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
5494 struct_posix_tm t_data;
5495 struct_posix_tm* t = NULL;
5496 char t_zone[6] = { 0, 0, 0, 0, 0, 0 };
5508 buf = (
char*) posix_malloc(len);
5512 #if CFG_USE_POSIX_API >= 200112
5515 t = posix_localtime_r(&ts, &t_data);
5519 if(posix_strftime(t_zone, 6,
"%z", t)) { fallback = 0; }
5526 t = posix_gmtime_r(&ts, &t_data);
5527 if(NULL == t) { error = 1; }
5528 else { strcpy(t_zone,
"-0000"); }
5532 rv = posix_snprintf(buf, len,
"%s, %d %s %04d %02d:%02d:%02d %s",
5533 weekday[t->tm_wday],
5534 t->tm_mday, months[t->tm_mon], t->tm_year + 1900,
5535 t->tm_hour, t->tm_min, t->tm_sec, t_zone);
5536 if(!(30 <= rv && 31 >= rv))
5538 PRINT_ERROR(
"Created date and time string is invalid (bug)");
5543 #if CFG_USE_XSI || CFG_USE_POSIX_API >= 200112
5550 if(!posix_strftime(t_zone, 6,
"%Z", t))
5552 PRINT_ERROR(
"Creating timezone name comment failed");
5557 strcat(buf, t_zone);
5568 posix_free((
void*) buf);
5631 const char datext[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
5632 "0123456789" "!#$%&'*+-/=?^_`{|}~" ".";
5637 unsigned long int r;
5638 unsigned long int pid;
5641 unsigned char secs[6];
5642 unsigned char rpp[6];
5643 const char* buf_date = NULL;
5644 const char* buf_rpp = NULL;
5648 if(NULL == fqdn) { error = 1; }
5652 if(!len) { error = 1; }
5654 else if( len != strspn(fqdn, datext)
5656 ||
'.' == fqdn[len - (
size_t) 1] )
5658 PRINT_ERROR(
"Invalid FQDN format (dot-atom syntax required)");
5672 len += strlen(CFG_NAME);
5674 len += strlen(fqdn);
5677 if((
size_t) 251 < len)
5679 PRINT_ERROR(
"Invalid message ID (FQDN too long)");
5690 secs[2] = (
unsigned char) (ts_int >> 24);
5691 secs[3] = (
unsigned char) (ts_int >> 16);
5692 secs[4] = (
unsigned char) (ts_int >> 8);
5693 secs[5] = (
unsigned char) (ts_int & 0xFFU);
5695 if(rv) { error = 1; }
5700 r = (
unsigned long int) posix_random();
5701 rpp[0] = (
unsigned char) (r >> 8);
5702 rpp[1] = (
unsigned char) (r & 0xFFU);
5703 pid = (
unsigned long int) posix_getpid();
5704 rpp[2] = (
unsigned char) (pid >> 24);
5705 rpp[3] = (
unsigned char) (pid >> 16);
5706 rpp[4] = (
unsigned char) (pid >> 8);
5707 rpp[5] = (
unsigned char) (pid & 0xFFU);
5709 if(rv) { error = 1; }
5714 buf = (
char*) posix_malloc(len);
5719 strcat(buf, buf_date);
5720 strcat(buf, buf_rpp);
5721 strcat(buf,
".A3." CFG_NAME
"@");
5730 for(i = 0; len > i; ++i)
5732 if(
'@' == buf[i]) {
break; }
5733 if(
'/' == buf[i]) { buf[i] =
'-'; }
5738 fprintf(stderr,
"%s: %sFunction core_get_msgid() returned error\n",
5766 const char* confdir = NULL;
5767 const char* spn = NULL;
5769 const char* scheme_string = NULL;
5770 const char* sec = NULL;
5774 const char* mac_enc;
5783 scheme_string =
"sha1:";
5789 scheme_string =
"sha256:";
5794 PRINT_ERROR(
"Scheme requested for Cancel-Key not supported");
5799 if(NULL != scheme_string)
5813 rv =
hmac_sha1_160(msgid, strlen(msgid), sec, strlen(sec), mac);
5833 fprintf(stderr,
"%s: %sCL secret file: %s\n",
5839 posix_free((
void*) spn); spn = NULL;
5858 fprintf(stderr,
"%s: %sSize of CL secret: %u"
5860 (
unsigned int) len);
5862 if((
size_t) 32 > len)
5865 "SHA256 too short");
5890 len = strlen(scheme_string);
5891 len += strlen(mac_enc);
5892 res = (
char*) posix_malloc(++len);
5895 strcpy(res, scheme_string);
5896 strcat(res, mac_enc);
5927 const char* scheme_string = NULL;
5928 const char* ckey = NULL;
5929 const char* key = NULL;
5941 scheme_string =
"sha1:";
5947 scheme_string =
"sha256:";
5952 PRINT_ERROR(
"Scheme requested for Cancel-Lock not supported");
5957 if(NULL != scheme_string)
5962 len = strlen(scheme_string);
5964 if(strlen(ckey) < len || strncmp(ckey, scheme_string, len))
5966 PRINT_ERROR(
"Cancel-Key has unsupported scheme (bug)");
5968 else { key = &ckey[len]; }
5995 len += strlen(md_enc);
5996 res = (
char*) posix_malloc(++len);
5999 strcpy(res, scheme_string);
6000 strcat(res, md_enc);
6008 posix_free((
void*) ckey);
6037 const char* homedir = NULL;
6038 const char sigdir[] =
"/";
6039 char* sigpathname = NULL;
6040 const char* sigfile = NULL;
6044 unsigned int warn_flags = 0;
6066 sigpathname = (
char*) posix_malloc(strlen(homedir) + strlen(sigdir)
6067 + strlen(sigfile) + (size_t) 1);
6068 if(NULL == sigpathname)
6071 "Cannot allocate memory for config file pathname");
6075 strcpy(sigpathname, homedir);
6076 strcat(sigpathname, sigdir);
6077 strcat(sigpathname, sigfile);
6084 rv =
fu_open_file(sigpathname, &fd, POSIX_O_RDONLY, 0);
6088 if(rv) { res = NULL; }
6095 posix_free((
void*) sigpathname);
6096 posix_free((
void*) homedir);
6098 else {
PRINT_ERROR(
"Environment variable 'HOME' is not defined"); }
6104 if(strncmp(res,
"-- \n", (
size_t) 4))
6114 if(len) { lines = 1; }
6115 for(i = 0; i < len; ++i)
6119 if(i + (
size_t) 1 != len)
6121 if(POSIX_SIZE_MAX > lines) { ++lines; }
6127 *warnings = warn_flags;
6159 const char* c1 = NULL;
6160 const char* c2 = NULL;
6165 res = (
char*) posix_malloc((
size_t) 998);
6170 fmt = (
char*) posix_malloc(strlen(cfg) + (size_t) 1);
6171 if (NULL == fmt) { error = 1; }
6175 p = strchr(fmt, (
int)
'%');
6179 if(
's' == p[1]) { c1 = ca; }
6180 else if(
'g' == p[1]) { p[1] =
's'; c1 = ngl; }
6184 p = strchr(&p[2], (
int)
'%');
6188 if(
's' == p[1]) { c2 = ca; }
6189 else if(
'g' == p[1]) { p[1] =
's'; c2 = ngl; }
6193 if(NULL != strchr(&p[2], (
int)
'%'))
6195 fprintf(stderr,
"%s: %s"
6196 "More than 2 conversions in introduction line "
6203 fprintf(stderr,
"%s: %s"
6204 "Conversion type in introduction line not "
6213 len = posix_snprintf(res, 998, fmt, c1, c2);
6214 if(0 >= len) { error = 1; }
6216 posix_free((
void*) fmt);
6221 posix_free((
void*) res);
6253 size_t len = strlen(pathname) + (size_t) 1;
6259 res = (
char*) posix_malloc(len);
6264 case FILTER_CS_UTF_8:
6268 if(NULL == rv) { error = 1; }
6271 if(len <= strlen(rv)) { error = 1; }
6272 else { strcpy(res, rv); }
6273 if(rv != pathname) {
enc_free((
void*) rv); }
6277 case FILTER_CS_ISO8859_1:
6281 if(NULL == rv) { error = 1; }
6286 if(NULL == rv2) { error = 1; }
6293 else { strcpy(res, rv2); }
6294 if(rv2 != rv) {
enc_free((
void*) rv2); }
6296 if(rv != pathname) {
enc_free((
void*) rv); }
6300 case FILTER_CS_ASCII:
6303 else { strcpy(res, pathname); }
6318 PRINT_ERROR(
"Pathname conversion to codeset of locale failed");
6319 posix_free((
void*) res);
6374 int flags = POSIX_O_WRONLY | POSIX_O_CREAT | POSIX_O_TRUNC;
6375 posix_mode_t perm = POSIX_S_IRUSR | POSIX_S_IWUSR |
6376 POSIX_S_IRGRP | POSIX_S_IWGRP |
6377 POSIX_S_IROTH | POSIX_S_IWOTH;
6388 if(!res) { fprintf(fs,
"%s", s); }
6417 #define CORE_PID_MAXLEN (size_t) 32
6418 char* tmppathname = NULL;
6421 const char* tmpdir = NULL;
6424 long int len_pn_max;
6427 char pid_string[CORE_PID_MAXLEN];
6436 len = strlen(tmpdir);
6437 pn = posix_malloc(++len);
6438 if(NULL != pn) { strcpy(pn, tmpdir); }
6439 if(0 <= rv) { posix_free((
void*) tmpdir); }
6444 len_pn = strlen(pn);
6445 len_pn_max = posix_pathconf(pn, POSIX_PC_NAME_MAX);
6449 PRINT_ERROR(
"Temporary file pathname length check failed");
6453 if(POSIX_LONG_MAX > len_pn_max)
6459 len = strlen(CFG_NAME);
6461 pid = (
long int) posix_getpid();
6462 rv = posix_snprintf(pid_string, CORE_PID_MAXLEN,
"%ld", pid);
6463 if(0 > rv || CORE_PID_MAXLEN <= (
size_t) rv) { error = 1; }
6468 if((
size_t) len_pn_max >= len)
6472 tmppathname = posix_realloc((
void*) pn, ++len_pn);
6473 if(NULL == tmppathname) { error = 1; }
6476 strcat(tmppathname,
"/" CFG_NAME
"_");
6477 strcat(tmppathname, pid_string);
6478 strcat(tmppathname,
"_XXXXXX");
6487 " (truncated and no longer unique)");
6489 tmppathname = posix_realloc((
void*) pn, ++len_pn);
6490 if(NULL == tmppathname)
6492 posix_free((
void*) pn);
6496 strncat(tmppathname,
"/" CFG_NAME, (
size_t) 8);
6497 strcat(tmppathname,
"_XXXXXX");
6503 if(NULL != tmppathname)
6505 rv = posix_mkstemp(tmppathname);
6509 posix_free((
void*) tmppathname);
6515 return(tmppathname);
6532 if(NULL != pathname)
6535 posix_free((
void*) pathname);
6548 n->nntp_state = CORE_NEXUS_CLOSED;
6566 rv = posix_pthread_mutex_lock(&pt_mutex);
6582 rv = posix_pthread_mutex_unlock(&pt_mutex);
6603 rv = posix_pthread_equal(ui_pt, posix_pthread_self());
6604 if(rv) { res = 1; }
else { res = 0; }
6644 posix_sigset_t sigmask;
6645 posix_sigset_t oldmask;
6648 ui_pt = posix_pthread_self();
6651 posix_sigemptyset(&sigmask);
6652 posix_sigaddset(&sigmask, POSIX_SIGINT);
6653 posix_sigaddset(&sigmask, POSIX_SIGQUIT);
6654 posix_sigaddset(&sigmask, POSIX_SIGTERM);
6655 res = posix_pthread_sigmask(POSIX_SIG_BLOCK, &sigmask, &oldmask);
6656 if(res) {
PRINT_ERROR(
"Setting signal mask failed"); }
6668 posix_srandom((
unsigned int) posix_getpid());
6670 res = posix_pthread_create(&pt, NULL, core_main, NULL);
6671 if(res) {
PRINT_ERROR(
"Spawning thread failed"); }
6676 res = posix_pthread_sigmask(POSIX_SIG_SETMASK, &oldmask, NULL);
6708 rv = commands_in_queue(10U, 100U);
6709 if(rv) {
PRINT_ERROR(
"Command queue drain timeout"); }
6717 command = CORE_TERMINATE_NEXUS;
6718 rv = posix_pthread_cond_signal(&pt_cond);
6719 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
6723 rv = commands_in_queue(10U, 100U);
6724 if(rv) {
PRINT_ERROR(
"Nexus termination failed"); }
6728 rv = posix_pthread_cancel(pt);
6729 if(rv) {
PRINT_ERROR(
"Cancelling core thread failed"); }
6734 rv = posix_pthread_join(pt, NULL);
6735 if(rv) {
PRINT_ERROR(
"Joining core thread failed"); }
6741 hierarchy_element_destructor(&h);