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 api_posix_pthread_t pt;
245 static int pt_valid = 0;
246 static api_posix_pthread_t ui_pt;
247 static api_posix_pthread_mutex_t pt_mutex = API_POSIX_PTHREAD_MUTEX_INITIALIZER;
248 static api_posix_pthread_cond_t pt_cond = API_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(API_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*) api_posix_malloc(len * (
size_t) 2 + (size_t) 1);
485 i = (size_t) (name - from);
488 memcpy(tmp, from, len); 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*) api_posix_malloc(len);
571 if (NULL == res) { res = from; }
577 api_posix_snprintf(res, len,
"<%s>", addr);
582 api_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 api_posix_free((
void*) from);
607 api_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 api_posix_malloc(asize *
sizeof(
struct core_headerfield));
724 if (NULL == *e) { res = -1; }
729 buf = (
char*) api_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*) api_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);
911 if(
'(' == buf[ii] && NULL == comment)
913 if(check_ic(buf, &buf[ii])) { comment = &buf[ii]; }
916 else if(NULL != comment &&
')' == buf[ii])
918 if(!check_ic(buf, &buf[ii + (
size_t) 1]))
921 len = strlen(&buf[++ii]);
922 memmove((
void*) comment, (
void*) &buf[ii], ++len);
923 ii = (size_t) (comment - buf);
937 if((
char) 0x09 == buf[ii]) { buf[ii] =
' '; }
938 if(ii &&
' ' == buf[ii])
940 if(
' ' == buf[ii - (
size_t) 1])
943 if( !( (
size_t) 2 <= ii
944 && 0x5C == (
int) buf[ii - (
size_t) 2]
945 && check_iqsc(buf, p) ) )
947 len = strlen(&buf[ii]);
948 memmove((
void*) p, (
void*) &buf[ii], ++len);
959 len = strlen(&buf[1]);
960 memmove((
void*) buf, (
void*) &buf[1], ++len);
963 if(CORE_HDR_CT == hf.id)
976 if(!inside_qs) { inside_qs = 1; }
980 if((
char) 0x5C != buf[ii - 1]) { inside_qs = 0; }
984 (
';' == buf[ii] ||
'=' == buf[ii] ||
'/' == buf[ii]))
986 if(
' ' == buf[ii - 1])
988 len = strlen(&buf[ii]);
989 memmove((
void*) &buf[ii - 1], (
void*) &buf[ii],
995 if(!inside_qs && (
'=' == buf[ii] ||
'/' == buf[ii]))
997 if(
' ' == buf[ii + 1])
999 len = strlen(&buf[ii + 2]);
1000 memmove((
void*) &buf[ii + 1], (
void*) &buf[ii + 2],
1007 else if(CORE_HDR_CTE == hf.id)
1016 " Content-Transfer-Encoding field ignored");
1022 else if(CORE_HDR_FROM == hf.id || CORE_HDR_REPLY2 == hf.id)
1025 if(CORE_HDR_REPLY2 == hf.id)
1028 do { gstart = strchr(q, (
int)
':'); q = gstart + 1; }
1029 while(NULL != gstart && check_iqsc(buf, gstart));
1033 do { gend = strchr(q, (
int)
';'); q = gend + 1; }
1034 while(NULL != gend && check_iqsc(buf, gend));
1039 do { p = strchr(q, (
int)
','); q = p + 1; }
1040 while(NULL != p && check_iqsc(buf, p));
1041 if(NULL == p || p > gstart)
1045 " address of address-list processed");
1047 while(++gstart < gend)
1050 if(
' ' != *gstart && 0x09 != (
int) *gstart)
1055 len = (size_t) (gend - gstart);
1056 memmove((
void*) buf, (
void*) gstart, ++len);
1063 do { p = strchr(q, (
int)
','); q = p + 1; }
1064 while(NULL != p && check_iqsc(buf, p));
1067 PRINT_ERROR(
"Header parser: Only first mailbox of"
1068 " mailbox-list processed");
1072 p = strrchr(buf, (
int)
'<');
if(NULL == p) { p = buf; }
1076 if(&buf[ii] < p) { ++ii;
continue; }
1077 if(ii &&
' ' == buf[ii])
1080 if(
'<' == buf[ii - (
size_t) 1]
1081 ||
'@' == buf[ii - (
size_t) 1]
1082 ||
'>' == buf[ii + (
size_t) 1]
1083 ||
'@' == buf[ii + (
size_t) 1] )
1086 len = strlen(&buf[++ii]);
1087 memmove((
void*) p, (
void*) &buf[ii], ++len);
1094 #if !CORE_UAGENT_RAW
1096 else if(CORE_HDR_UAGENT == hf.id)
1102 if(ii &&
' ' == buf[ii])
1105 if(
'/' == buf[ii - (
size_t) 1]
1106 ||
'/' == buf[ii + (
size_t) 1] )
1109 len = strlen(&buf[++ii]);
1110 memmove((
void*) p, (
void*) &buf[ii], ++len);
1119 if(CORE_HDR_UAGENT != hf.id)
1128 if(
'"' == buf[ii]) { qstring = !qstring; skip = 1; }
1129 if(qstring && (
char) 0x5C == buf[ii]) { skip = 2; }
1133 len = strlen(&buf[++ii]);
1134 memmove((
void*) p, (
void*) &buf[ii], ++len);
1136 if(1 == skip) { --ii; }
1154 if(ai >= asize - (
size_t) 2)
1156 tmp = (
struct core_headerfield*)
1157 api_posix_realloc(*e, (asize *= (
size_t) 2)
1158 *
sizeof(
struct core_headerfield));
1159 if (NULL == tmp) { res = -1;
break; }
else { *e = tmp; }
1161 (*e)[ai].id = hf.id;
1162 (*e)[ai++].content = hf.content;
1165 buf = (
char*) api_posix_malloc(buflen);
1166 if (NULL == buf) { res = -1;
break; }
1173 target = strchr(&h[i], 0x0D);
1176 PRINT_ERROR(
"Header parser: Body separator missing");
1180 else { i += (size_t) (++target - &h[i]);}
1182 if((
const char) 0x0A == h[i]) { ++i; }
1184 if((
const char) 0x0D == h[i])
1186 if((
const char) 0x0A == h[i + 1])
1195 while(h[i] && (
' ' == h[i] || (
const char) 0x09 == h[i]));
1198 if(*e) { (*e)[ai].id = CORE_HDR_EOH; }
1201 api_posix_free((
void*) buf);
1207 while(CORE_HDR_EOH != (*e)[ai].
id)
1209 api_posix_free((
void*) (*e)[ai++].content);
1211 api_posix_free((
void*) *e);
1221 for(i = 0; i < 80; ++i) { printf(
"-"); } printf(
"\n");
1223 while(CORE_HDR_EOH != (*e)[ai].
id)
1228 if(hfieldids[i] == (*e)[ai].
id) {
break; }
1230 while(hfieldids[i++]);
1231 printf(
"%s: %s\n", hfields[i], (*e)[ai].content);
1234 for(i = 0; i < 80; ++i) { printf(
"-"); } printf(
"\n");
1252 static const char** extract_groups(
const char* body)
1254 const char** res = NULL;
1270 if(!body[i] ||
',' == body[i] ||
' ' == body[i]
1271 || (
const char) 0x09 == body[i])
1277 if (ne < ns) {
continue; }
1278 else { len = ne - ns; }
1279 group = (
char*) api_posix_malloc(len + (
size_t) 1);
1280 if(NULL == group) { err = 1;
break; }
1281 memcpy(group, &body[ns], len);
1285 if(API_POSIX_SIZE_MAX == asize) { err = 1;
break; }
1286 len = (asize + (size_t) 1) *
sizeof(
const char*);
1291 if(!bsize) { bsize =
sizeof(
const char*); }
1292 p = api_posix_realloc((
void*) res, bsize *= (
size_t) 2);
1293 if(NULL == p) { err = 1;
break; }
1296 res[asize - (size_t) 1] = (
const char*) group;
1297 res[asize++] = NULL;
1302 else {
if(!p_flag) { ns = i; p_flag = 1; } }
1309 api_posix_free((
void*) group);
1312 for(i = 0; i < asize; ++i) { api_posix_free((
void*) res[i]); }
1313 api_posix_free((
void*) res);
1333 static const char** extract_refs(
const char* body)
1335 const char** res = NULL;
1357 if(!body[i] ||
' ' == body[i] ||
'<' == body[i])
1366 "Invalid index in References (Bug)");
1372 if((
size_t) 2 > len || (
size_t) 250 < len)
1375 "Invalid length of MID in References");
1378 if(
'>' != body[ne - (
size_t) 1]) {
continue; }
1381 if(cfws_warn &&
'<' == body[i])
1383 PRINT_ERROR(
"Header parser: CFWS missing in References");
1386 msgid = (
char*) api_posix_malloc(len + (
size_t) 1);
1387 if(NULL == msgid) { err = 1;
break; }
1388 memcpy(msgid, &body[ns], len);
1392 if(API_POSIX_SIZE_MAX == asize) {
break; }
1393 len = (asize + (size_t) 1) *
sizeof(
const char*);
1398 if(!bsize) { bsize =
sizeof(
const char*); }
1399 p = api_posix_realloc((
void*) res, bsize *= (
size_t) 2);
1400 if(NULL == p) {
break; }
1403 res[asize - (size_t) 1] = (
const char*) msgid;
1404 res[asize++] = NULL;
1410 if(
'<' == body[i]) { ns = i; p_flag = 1; }
1418 for(i = 0; i < asize; ++i) { api_posix_free((
void*) res[i]); }
1419 api_posix_free((
void*) res);
1437 api_posix_free((
void*) (*ahp)->msgid);
1438 if(NULL != (*ahp)->groups)
1441 while(NULL != (*ahp)->groups[i])
1443 api_posix_free((
void*) (*ahp)->groups[i++]);
1445 api_posix_free((
void*) (*ahp)->groups);
1447 api_posix_free((
void*) (*ahp)->from);
1448 api_posix_free((
void*) (*ahp)->subject);
1450 api_posix_free((
void*) (*ahp)->supers);
1451 api_posix_free((
void*) (*ahp)->fup2);
1452 api_posix_free((
void*) (*ahp)->reply2);
1453 api_posix_free((
void*) (*ahp)->uagent);
1454 api_posix_free((
void*) (*ahp)->org);
1455 if(NULL != (*ahp)->refs)
1458 while(NULL != (*ahp)->refs[i])
1460 api_posix_free((
void*) (*ahp)->refs[i++]);
1462 api_posix_free((
void*) (*ahp)->refs);
1464 api_posix_free((
void*) (*ahp)->dist);
1465 api_posix_free((
void*) (*ahp)->mime_v);
1466 api_posix_free((
void*) (*ahp)->mime_ct);
1467 api_posix_free((
void*) (*ahp)->mime_cte);
1468 api_posix_free((
void*) (*ahp)->mime_cd);
1469 api_posix_free((
void*) (*ahp)->x_newsr);
1470 api_posix_free((
void*) (*ahp)->x_mailer);
1471 api_posix_free((
void*) (*ahp)->x_pagent);
1475 api_posix_free((
void*) *ahp);
1489 #define CORE_GET_EMPTY_STRING(p) \
1491 p = (char*) api_posix_malloc(1); \
1492 if(NULL == p) { res = -1; } \
1493 else { ((char*) p)[0] = 0; } \
1496 #define CORE_GET_ERROR_STRING(p) \
1498 p = (char*) api_posix_malloc(34); \
1499 if(NULL == p) { res = -1; } \
1500 else { strcpy((char*) p, "[Missing or invalid header field]"); } \
1506 struct core_headerfield* e = NULL;
1512 res = header_parser(&e, h);
1518 if(NULL == *ahp) { res = -1; }
1523 (*ahp)->msgid = NULL;
1524 (*ahp)->groups = NULL;
1525 (*ahp)->from = NULL;
1526 (*ahp)->subject = NULL;
1529 (*ahp)->supers = NULL;
1530 (*ahp)->fup2 = NULL;
1531 (*ahp)->reply2 = NULL;
1532 (*ahp)->uagent = NULL;
1534 (*ahp)->refs = NULL;
1535 (*ahp)->dist = NULL;
1536 (*ahp)->mime_v = NULL;
1537 (*ahp)->mime_ct = NULL;
1538 (*ahp)->mime_cte = NULL;
1539 (*ahp)->mime_cd = NULL;
1540 (*ahp)->x_newsr = NULL;
1541 (*ahp)->x_mailer = NULL;
1542 (*ahp)->x_pagent = NULL;
1547 while(CORE_HDR_EOH != e[i].
id)
1551 case CORE_HDR_MSGID:
1555 (*ahp)->msgid = e[i].content;
1556 e[i].content = NULL;
1560 case CORE_HDR_GROUPS:
1564 (*ahp)->groups = extract_groups(e[i].content);
1574 if(!rv) { mime = 1; }
1575 else { mime_s = e[i].content; e[i].content = NULL; }
1576 (*ahp)->from = mime_s;
1580 case CORE_HDR_SUBJECT:
1582 if(!(*ahp)->subject)
1585 if(!rv) { mime = 1; }
1586 else { mime_s = e[i].content; e[i].content = NULL; }
1587 (*ahp)->subject = mime_s;
1599 case CORE_HDR_SUPERS:
1603 (*ahp)->supers = e[i].content;
1604 e[i].content = NULL;
1612 (*ahp)->fup2 = e[i].content;
1613 e[i].content = NULL;
1617 case CORE_HDR_REPLY2:
1622 if(!rv) { mime = 1; }
1623 else { mime_s = e[i].content; e[i].content = NULL; }
1624 (*ahp)->reply2 = mime_s;
1628 case CORE_HDR_UAGENT:
1633 if(!rv) { mime = 1; }
1634 else { mime_s = e[i].content; e[i].content = NULL; }
1635 (*ahp)->uagent = mime_s;
1644 if(!rv) { mime = 1; }
1645 else { mime_s = e[i].content; e[i].content = NULL; }
1646 (*ahp)->org = mime_s;
1654 (*ahp)->refs = extract_refs(e[i].content);
1663 (*ahp)->dist = e[i].content;
1664 e[i].content = NULL;
1672 (*ahp)->mime_v = e[i].content;
1673 e[i].content = NULL;
1679 if(!(*ahp)->mime_ct)
1682 if(!rv) { mime = 1; }
1683 else { mime_s = e[i].content; e[i].content = NULL; }
1684 (*ahp)->mime_ct = mime_s;
1691 if(!(*ahp)->mime_cte)
1693 (*ahp)->mime_cte = e[i].content;
1694 e[i].content = NULL;
1700 if(!(*ahp)->mime_cd)
1703 if(rv) { mime_s = e[i].content; e[i].content = NULL; }
1704 (*ahp)->mime_cd = mime_s;
1708 case CORE_HDR_X_NEWSR:
1710 if(!(*ahp)->x_newsr)
1713 if(!rv) { mime = 1; }
1714 else { mime_s = e[i].content; e[i].content = NULL; }
1715 (*ahp)->x_newsr = mime_s;
1719 case CORE_HDR_X_MAILER:
1721 if(!(*ahp)->x_mailer)
1724 if(!rv) { mime = 1; }
1725 else { mime_s = e[i].content; e[i].content = NULL; }
1726 (*ahp)->x_mailer = mime_s;
1730 case CORE_HDR_X_PAGENT:
1732 if(!(*ahp)->x_pagent)
1735 if(!rv) { mime = 1; }
1736 else { mime_s = e[i].content; e[i].content = NULL; }
1737 (*ahp)->x_pagent = mime_s;
1741 case CORE_HDR_LINES:
1761 while(CORE_HDR_EOH != e[i].
id)
1763 api_posix_free((
void*) e[i++].content);
1765 api_posix_free((
void*) e);
1770 if(NULL == (*ahp)->msgid) { CORE_GET_EMPTY_STRING((*ahp)->msgid); }
1771 if(NULL == (*ahp)->groups)
1773 (*ahp)->groups = (
const char**)
1774 api_posix_malloc(
sizeof(
const char*) * (size_t) 2);
1775 if(NULL != (*ahp)->groups)
1777 CORE_GET_EMPTY_STRING((*ahp)->groups[0]);
1778 (*ahp)->groups[1] = NULL;
1781 if(NULL == (*ahp)->from) { CORE_GET_ERROR_STRING((*ahp)->from); }
1782 if(NULL == (*ahp)->subject)
1784 CORE_GET_ERROR_STRING((*ahp)->subject);
1789 if(res) { header_object_destructor(ahp); }
1798 "MIME-Version field missing, but MIME is used");
1817 if(NULL == *he) { res = -1; }
1822 (*he)->flags =
flags;
1823 (*he)->header = NULL;
1824 (*he)->parent = NULL;
1825 (*he)->children = 0;
1826 (*he)->child = NULL;
1841 header_object_destructor(&(*he)->header);
1843 api_posix_free((
void*) (*he)->child);
1845 api_posix_free((
void*) *he);
1865 if(!root) { res = -1; }
1873 while((*current)->children)
1876 current = &(*current)->
child[(*current)->children - (size_t) 1];
1879 hierarchy_element_destructor(current);
1882 res = hierarchy_element_constructor(root, 0, 0);
1900 for(i = 0; i < root->
children; ++i)
1904 res = root->
child[i];
1910 tmp = hierarchy_find_article(msgid, root->
child[i]);
1911 if(tmp != root->
child[i])
1932 if(a_date < b_date) { res = -1; }
1933 if(a_date > b_date) { res = 1; }
1938 if(a_date < b_date) { res = 1; }
1939 if(a_date > b_date) { res = -1; }
1956 const char supers_subject[] =
"[Superseded]";
1963 if(NULL == *root) { res = -1; }
1968 res = hierarchy_element_constructor(&he_new, num,
flags);
1972 res = header_object_constructor(&he_new->
header,
header);
1978 printf(
"%s: %sAdded article %s to hierarchy: %s\n",
1984 if(0 > res) { api_posix_free((
void*) he_new); }
1993 he_super = hierarchy_find_article(he_new->
header->
supers, *root);
1994 if(he_super != *root)
1997 size = strlen(supers_subject);
1998 tmp = (
char*) api_posix_realloc((
void*) he_super->
header->
subject,
2002 PRINT_ERROR(
"Memory allocation for subject field failed");
2006 strcpy(tmp, supers_subject);
2020 while(NULL != he_new->
header->
refs[i]) { ++i; };
2023 he_parent = hierarchy_find_article(he_new->
header->
refs[--i],
2025 if(he_parent != *root) {
break; }
2029 size = (he_parent->
children + (size_t) 1)
2032 api_posix_realloc(he_parent->
child, size);
2033 if(NULL == he_tmp) { res = -1; }
2035 if(res) { hierarchy_element_destructor(&he_new); }
2038 he_parent->
child = he_tmp;
2039 he_new->
parent = he_parent;
2044 (int (*)(
const void*,
const void*)) hierarchy_sort_children);
2063 for(i = 0; i < root->
children; ++i)
2067 res = root->
child[i];
2073 tmp = hierarchy_find_element(num, root->
child[i]);
2094 if(NULL == *root) { res = -1; }
2099 he = hierarchy_find_element(num, *root);
2100 if(NULL == he) { res = -1; }
2104 if(!res) { res = header_object_constructor(&hdr, header); }
2109 header_object_destructor(&he->
header);
2120 static int nexus_constructor(
struct core_nexus** nexus,
const char* server)
2127 s = (
char*) api_posix_malloc(strlen(server) + (size_t) 1);
2131 *nexus = (
struct core_nexus*)
2132 api_posix_malloc(
sizeof(
struct core_nexus));
2133 if(NULL == *nexus) { api_posix_free((
void*) s); }
2136 (*nexus)->nntp_state = CORE_NEXUS_CLOSED;
2137 (*nexus)->nntp_server = s;
2138 (*nexus)->nntp_handle = -1;
2139 (*nexus)->nntp_current_group = NULL;
2152 static void nexus_destructor(
struct core_nexus** nexus)
2156 if(NULL != (*nexus)->nntp_server)
2158 api_posix_free((
void*) (*nexus)->nntp_server);
2160 if(NULL != (*nexus)->nntp_current_group)
2162 api_posix_free((
void*) (*nexus)->nntp_current_group);
2164 api_posix_free((
void*) *nexus);
2173 static int nexus_open(
struct core_nexus** nexus)
2187 printf(
"%s: %sProtocol logfile: %s\n",
2197 api_posix_free((
void*) logpathname);
2214 res =
nntp_open(&(*nexus)->nntp_handle, (*nexus)->nntp_server,
2215 service, logpathname, enc, auth);
2222 PRINT_ERROR(
"Authentication with empty password rejected");
2227 res =
nntp_open(&(*nexus)->nntp_handle, (*nexus)->nntp_server,
2228 service, logpathname, enc, auth,
2235 PRINT_ERROR(
"Authentication algorithm not supported");
2240 if (0 > res) { (*nexus)->nntp_state = CORE_NEXUS_CLOSED; }
2241 else { (*nexus)->nntp_state = CORE_NEXUS_ESTABLISHED; }
2244 api_posix_free((
void*) logpathname);
2257 static void nexus_close(
struct core_nexus** nexus)
2262 if(-1 != (*nexus)->nntp_handle)
2267 nexus_destructor(nexus);
2277 static int nexus_handler(
struct core_nexus** nexus)
2282 if(NULL == *nexus) { res = -1; }
2283 else if(CORE_NEXUS_ESTABLISHED != (*nexus)->nntp_state) { res = -1; }
2287 res = nexus_open(nexus);
2291 if(NULL != (*nexus)->nntp_current_group)
2293 nntp_set_group((*nexus)->nntp_handle, (*nexus)->nntp_current_group,
2313 static int check_connection(
int r)
2323 n->nntp_state = CORE_NEXUS_CLOSED;
2326 else if(-3 == r) { res = -1; }
2335 static void get_motd(
void)
2344 res = nexus_handler(&n);
2355 if(check_connection(res)) {
break; }
2357 while(res && retries--);
2365 static void get_distrib_pats(
void)
2369 const char* d_pats = NULL;
2374 res = nexus_handler(&n);
2385 if(check_connection(res)) {
break; }
2387 while(res && retries--);
2395 static void get_subscriptions(
void)
2404 res = nexus_handler(&n);
2415 if(check_connection(res)) {
break; }
2417 while(res && retries--);
2425 static void reset_group_states(
void)
2433 if(!res) { res = rv; }
2442 static void get_group_list(
void)
2451 res = nexus_handler(&n);
2461 if(check_connection(res)) {
break; }
2463 while(0 > res && retries--);
2471 static void get_group_labels(
void)
2480 res = nexus_handler(&n);
2490 if(check_connection(res)) {
break; }
2492 while(0 > res && retries--);
2500 static void get_groupinfo(
void)
2524 gl = (
const char**) api_posix_malloc(gc *
sizeof(
const char*));
2527 for(i = 0; i < gc; ++i) { gl[i] = (*gs)[i].name; }
2529 api_posix_free((
void*) gl);
2533 res = nexus_handler(&n);
2539 if(NULL == garray) { res = -1;
break; }
2541 for(i = 0; i < gc; ++i)
2548 if(-2 == res) {
break; }
2558 if(NULL == gd) {
break; }
2561 memcpy((
void*) &garray[i], (
void*) gd,
2564 memcpy((
void*) &garray[i].
name, (
void*) &(*gs)[i].
name,
2565 sizeof(
const char*));
2566 api_posix_free((
void*) gd);
2571 api_posix_free((
void*) garray);
2574 else {
data.
data = (
void*) garray; }
2575 if(check_connection(res)) {
break; }
2577 while(0 > res && retries--);
2586 static void set_group(
void)
2597 res = nexus_handler(&n);
2609 gn = (
char*) api_posix_malloc(++len);
2610 if(NULL == gn) { n->nntp_current_group = NULL; }
2614 if(NULL != n->nntp_current_group)
2616 api_posix_free((
void*) n->nntp_current_group);
2618 n->nntp_current_group = (
const char*) gn;
2631 if(check_connection(res)) {
break; }
2633 while(res && retries--);
2641 static void get_overview(
void)
2646 char* overview = NULL;
2651 res = nexus_handler(&n);
2663 if(check_connection(res)) {
break; }
2665 while(res && retries--);
2673 static void get_article_by_mid(
void)
2677 char* article = NULL;
2682 res = nexus_handler(&n);
2694 if(check_connection(res)) {
break; }
2696 while(res && retries--);
2704 static void get_article(
void)
2708 char* article = NULL;
2713 res = nexus_handler(&n);
2725 if(check_connection(res)) {
break; }
2727 while(res && retries--);
2735 static void get_article_header(
void)
2739 char* header = NULL;
2744 res =
db_read(n->nntp_current_group, *anum, &header, &len);
2756 res = nexus_handler(&n);
2770 db_add(n->nntp_current_group, *anum, header, strlen(header));
2786 if(check_connection(res)) {
break; }
2788 while(res && retries--);
2797 static void get_article_body(
void)
2806 res = nexus_handler(&n);
2819 if(check_connection(res)) {
break; }
2821 while(res && retries--);
2829 static void post_article(
void)
2836 res = nexus_handler(&n);
2841 if(check_connection(res)) {
break; }
2843 while(res && retries--);
2855 static void cleanup_handler(
void* arg)
2873 static void* core_main(
void* arg)
2880 api_posix_pthread_cleanup_push(cleanup_handler, NULL);
2887 rv = api_posix_pthread_cond_wait(&pt_cond, &pt_mutex);
2897 case CORE_CMD_GET_MOTD:
2902 case CORE_CMD_GET_DISTRIB_PATS:
2907 case CORE_CMD_GET_SUBSCRIPTIONS:
2909 get_subscriptions();
2912 case CORE_CMD_RESET_GROUPSTATES:
2914 reset_group_states();
2917 case CORE_CMD_GET_GROUPLIST:
2922 case CORE_CMD_GET_GROUPLABELS:
2927 case CORE_CMD_GET_GROUPINFO:
2932 case CORE_CMD_SET_GROUP:
2937 case CORE_CMD_GET_OVERVIEW:
2942 case CORE_CMD_GET_ARTICLE_BY_MID:
2944 get_article_by_mid();
2947 case CORE_CMD_GET_ARTICLE:
2952 case CORE_CMD_GET_ARTICLE_HEADER:
2954 get_article_header();
2957 case CORE_CMD_GET_ARTICLE_BODY:
2962 case CORE_CMD_POST_ARTICLE:
2968 case CORE_TERMINATE_NEXUS:
2986 command = CORE_CMD_INVALID;
2994 api_posix_pthread_cleanup_pop(1);
3007 static int commands_in_queue(
unsigned int checks,
unsigned int to)
3014 for(i = 0; i < checks; ++i)
3019 rv = api_posix_pthread_mutex_trylock(&pt_mutex);
3022 if(CORE_CMD_INVALID == command)
3042 static void core_distrib_pats_destructor(
struct distrib_pats*** pats)
3046 if(NULL != pats && NULL != *pats)
3048 while(NULL != (*pats)[i])
3050 api_posix_free((
void*) (*pats)[i]->wildmat);
3051 api_posix_free((
void*) (*pats)[i]->dist);
3052 api_posix_free((
void*) (*pats)[i++]);
3054 api_posix_free((
void*) *pats);
3082 static int core_distrib_pats_constructor(
struct distrib_pats*** pats,
3086 size_t sosp =
sizeof(
struct distrib_pats*);
3093 unsigned long int weight;
3094 char* wildmat = NULL;
3096 struct distrib_pats* element = NULL;
3097 struct distrib_pats**
object = NULL;
3100 struct distrib_pats* tmp2;
3101 struct distrib_pats** tmp3;
3108 tmp3 = (
struct distrib_pats**) api_posix_malloc(sosp);
3122 p = strchr(&raw[i], 0x0A);
3126 if(NULL !=
object) { res = 0; }
3131 line_len = (size_t) (p - &raw[i]);
3134 tmp = (
char*) api_posix_realloc(line, line_len + (
size_t) 1);
3135 if(NULL == tmp) {
break; }
3139 strncpy(line, &raw[i], line_len);
3142 tmp = (
char*) api_posix_realloc(wildmat, line_len + (
size_t) 1);
3143 if(NULL == tmp) {
break; }
else { wildmat = tmp; }
3144 tmp = (
char*) api_posix_realloc(dist, line_len + (
size_t) 1);
3145 if(NULL == tmp) {
break; }
else { dist = tmp; }
3146 rv = sscanf(line,
"%lu:%[^][\\:\r\n]:%s", &weight, wildmat, dist);
3149 PRINT_ERROR(
"Invalid distribution pattern ignored");
3154 tmp2 = (
struct distrib_pats*)
3155 api_posix_malloc(
sizeof(
struct distrib_pats));
3159 element->weight = weight;
3160 element->wildmat = wildmat; wildmat = NULL;
3161 element->dist = dist; dist = NULL;
3163 tmp3 = (
struct distrib_pats**)
3164 api_posix_realloc(
object, ++objects * sosp);
3167 api_posix_free((
void*) element->wildmat);
3168 api_posix_free((
void*) element->dist);
3169 api_posix_free((
void*) element);
3175 object[objects - 2] = element;
3176 object[objects - 1] = NULL;
3187 if(res && !raw[i] && NULL !=
object) { res = 0; }
3190 api_posix_free((
void*) line);
3191 api_posix_free((
void*) wildmat);
3192 api_posix_free((
void*) dist);
3193 api_posix_free((
void*) raw);
3196 if(res) { core_distrib_pats_destructor(&
object); }
3197 else { *pats = object; }
3222 static int core_check_line_length(
const char* article)
3232 p = strchr(&article[i], 0x0D);
3233 if(NULL == p) {
break; }
3234 len = p - &article[i];
3236 if(0x0A != (
int) article[i + len + (
size_t) 1])
3238 PRINT_ERROR(
"Invalid CR control character (not part of line break)");
3244 PRINT_ERROR(
"Article contains lines with more than 998 octets");
3248 i += len + (size_t) 1;
3249 if(article[i]) { ++i; }
3255 p = strchr(&article[i], 0x00);
3263 len = p - &article[i];
3266 PRINT_ERROR(
"Article contains lines with more than 998 octets");
3294 return(extract_groups(body));
3332 if(CORE_CMD_INVALID == command)
3336 command = CORE_CMD_GET_GROUPLIST;
3340 rv = api_posix_pthread_cond_signal(&pt_cond);
3341 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
3391 if(CORE_CMD_INVALID == command)
3395 command = CORE_CMD_GET_GROUPLABELS;
3399 rv = api_posix_pthread_cond_signal(&pt_cond);
3400 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
3451 PRINT_ERROR(
"Subscription rejected for invalid group name");
3481 if(!*num || *index > *num - (
size_t) 1) { res = -1; }
3484 api_posix_free((
void*) (*list)[*index].
name);
3486 if(*index < *num - (
size_t) 1)
3488 memmove((
void*) &(*list)[*index],
3489 (
void*) &(*list)[*index + (
size_t) 1],
3493 if(*index) { --*index; }
3527 if(CORE_CMD_INVALID == command)
3531 command = CORE_CMD_RESET_GROUPSTATES;
3535 rv = api_posix_pthread_cond_signal(&pt_cond);
3536 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
3594 size_t num_old = *num;
3596 size_t index_old = *index;
3609 if(num && num_old && NULL != *list && NULL != list_old)
3612 for(i = 0; i < *num; ++i)
3615 for(ii = 0; ii < num_old; ++ii)
3617 if(!strcmp((*list)[i].
name, list_old[ii].
name))
3619 (*list)[i].last_viewed = list_old[ii].
last_viewed;
3623 if(!strcmp((*list)[i].
name, list_old[index_old].
name))
3695 unsigned int cookie)
3702 if(CORE_CMD_INVALID == command)
3708 command = CORE_CMD_GET_GROUPINFO;
3712 rv = api_posix_pthread_cond_signal(&pt_cond);
3713 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
3742 api_posix_free((
void*) *list);
3778 if(CORE_CMD_INVALID == command)
3783 command = CORE_CMD_SET_GROUP;
3787 rv = api_posix_pthread_cond_signal(&pt_cond);
3788 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
3841 PRINT_ERROR(
"Server doesn't provide message of the day");
3846 if(CORE_CMD_INVALID == command)
3851 command = CORE_CMD_GET_MOTD;
3855 rv = api_posix_pthread_cond_signal(&pt_cond);
3856 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
3897 struct distrib_pats** pats = NULL;
3898 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
3909 api_posix_regex_t ere;
3917 PRINT_ERROR(
"Empty group list for distribution suggestions");
3921 PRINT_ERROR(
"Distribution suggestions disabled by configuration");
3929 api_posix_snprintf(x, (
size_t) 1024,
"%s",
"3:de.alt.test:de\r\n");
3937 PRINT_ERROR(
"Server doesn't provide distribution suggestions");
3941 if(!res) { res = core_distrib_pats_constructor(&pats,
data); }
3948 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
3950 while(NULL != groups[i])
3961 PRINT_ERROR(
"Unicode groupname ignored (not supported yet)");
3968 while(NULL != pats[ii])
3979 PRINT_ERROR(
"Unicode wildmat ignored (not supported yet)");
3990 for(iii = num; iii; --iii)
3993 rv = api_posix_regcomp(&ere, wma[iii - 1].ere,
3994 API_POSIX_REG_EXTENDED
3995 | API_POSIX_REG_NOSUB);
3998 PRINT_ERROR(
"Compiling regular expression failed");
4003 rv = api_posix_regexec(&ere, groups[i], 0, NULL, 0);
4004 api_posix_regfree(&ere);
4008 if(wma[iii - 1].negate)
4014 if(weight <= pats[ii]->weight)
4017 weight = pats[ii]->weight;
4033 len = strlen(pats[match]->dist);
4036 buf = (
char*) api_posix_malloc(++len);
4040 strcpy(buf, pats[match]->dist);
4047 p = (
char*) api_posix_realloc((
void*) buf, ++len + buf_len);
4053 strcat(buf, pats[match]->dist);
4062 PRINT_ERROR(
"Distribution pattern matching requires regular "
4063 "expression support");
4069 core_distrib_pats_destructor(&pats);
4073 if(!res) { printf(
"Suggested distribution: %s\n", *dist); }
4116 if(CORE_CMD_INVALID == command)
4121 command = CORE_CMD_GET_SUBSCRIPTIONS;
4125 rv = api_posix_pthread_cond_signal(&pt_cond);
4126 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
4185 if(CORE_CMD_INVALID == command)
4190 command = CORE_CMD_GET_OVERVIEW;
4194 rv = api_posix_pthread_cond_signal(&pt_cond);
4195 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
4249 if(CORE_CMD_INVALID == command)
4254 command = CORE_CMD_GET_ARTICLE_BY_MID;
4258 rv = api_posix_pthread_cond_signal(&pt_cond);
4259 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
4311 if(CORE_CMD_INVALID == command)
4316 command = CORE_CMD_GET_ARTICLE;
4320 rv = api_posix_pthread_cond_signal(&pt_cond);
4321 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
4373 if(CORE_CMD_INVALID == command)
4378 command = CORE_CMD_GET_ARTICLE_HEADER;
4382 rv = api_posix_pthread_cond_signal(&pt_cond);
4383 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
4435 if(CORE_CMD_INVALID == command)
4440 command = CORE_CMD_GET_ARTICLE_BODY;
4444 rv = api_posix_pthread_cond_signal(&pt_cond);
4445 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
4506 const char* a = NULL;
4507 const char* header = NULL;
4508 const char* body = NULL;
4513 const char hl_te[] =
"Content-Transfer-Encoding: 8bit\r\n";
4514 const char hl_ct[] =
"Content-Type: text/plain; charset=";
4515 const char hl_ct_ff[] =
"; format=fixed\r\n";
4516 const char* cs_iana =
"UTF-8";
4522 len = strlen(article);
4523 p = (
char*) api_posix_malloc(++len);
4526 PRINT_ERROR(
"Memory allocation for article failed");
4531 memcpy(p, article, len);
4541 PRINT_ERROR(
"Article encoding check/normalization failed");
4548 p = (
char*) api_posix_malloc(++len);
4551 PRINT_ERROR(
"Memory allocation for article failed");
4554 else { strcpy(p, a); }
4555 if(a != article) {
enc_free((
void*) a); }
4562 p = strstr(a,
"\r\n\r\n");
4565 PRINT_ERROR(
"Article to post contains no header separator");
4570 len = (size_t) (p - a) + (size_t) 2;
4571 q = (
char*) api_posix_malloc(++len);
4574 PRINT_ERROR(
"Memory allocation for article header failed");
4579 strncpy(q, a, --len); q[len] = 0;
4584 PRINT_ERROR(
"Article to post has invalid header encoding");
4594 len = strlen(&p[4]);
4595 q = (
char*) api_posix_malloc(++len);
4598 PRINT_ERROR(
"Memory allocation for article body failed");
4603 memcpy(q, &p[4], --len); q[len] = 0;
4617 p = (
char*) api_posix_malloc(++len);
4628 api_posix_free((
void*) body);
4640 len = strlen(header) + strlen(hl_te);
4641 len += strlen(hl_ct) + strlen(cs_iana) + strlen(hl_ct_ff);
4642 p = (
char*) api_posix_malloc(++len);
4645 PRINT_ERROR(
"Memory allocation for MIME header field failed");
4652 strcat(p, hl_ct); strcat(p, cs_iana); strcat(p, hl_ct_ff);
4653 api_posix_free((
void*) header);
4662 len += strlen(header);
4663 len += strlen(body);
4664 p = (
char*) api_posix_malloc(++len);
4667 PRINT_ERROR(
"Memory allocation for final article failed");
4675 api_posix_free((
void*) a);
4682 api_posix_free((
void*) header);
4683 api_posix_free((
void*) body);
4686 rv = core_check_line_length(a);
4687 if(rv) { res = -1; }
4697 if(res) { res = -1; }
4703 if(CORE_CMD_INVALID == command)
4709 command = CORE_CMD_POST_ARTICLE;
4712 rv = api_posix_pthread_cond_signal(&pt_cond);
4717 command = CORE_CMD_INVALID;
4731 if(0 >= res) { api_posix_free((
void*) a); }
4758 if(a >= cr->
first && a <= cr->
last) { res = 1;
break; }
4778 int before_current = 0;
4788 printf(
"\nGroup: %s\n", group->
name);
4791 printf(
" %lu-%lu\n", cr->
first, cr->
last);
4795 printf(
"Mark as read: %lu\n", a);
4798 if(NULL == cr) { new_range = 1; }
4804 if(a >= cr->
first && a <= cr->
last) {
break; }
4810 else { new_range = 1; before_current = 1; }
4816 if(NULL == cr->
next) { new_range = 1;
break; }
4817 else { cr = cr->
next; }
4826 if(NULL == cr) { group->
info = cr = nr; }
4833 memcpy((
void*) &tmp, (
void*) cr,
sizeof(
struct core_range));
4834 memcpy((
void*) cr, (
void*) nr,
sizeof(
struct core_range));
4835 memcpy((
void*) nr, (
void*) &tmp,
sizeof(
struct core_range));
4846 if(NULL != cr->
next)
4853 api_posix_free((
void*) nr);
4863 printf(
" %lu-%lu\n", cr->
first, cr->
last);
4892 printf(
"\nGroup: %s\n", group->
name);
4895 printf(
" %lu-%lu\n", cr->
first, cr->
last);
4899 printf(
"Mark as unread: %lu\n", a);
4914 if(NULL == lr) { group->
info = cr; }
4915 else { lr->
next = cr; }
4917 else if(a == cr->
first)
4922 else if(a == cr->
last)
4941 else { lr = cr; cr = cr->
next; }
4948 printf(
" %lu-%lu\n", cr->
first, cr->
last);
5065 if(NULL == hier) { hier = &h; }
5071 res = hierarchy_init(hier);
5076 if(NULL == *hier) { res = -1; }
5082 res = hierarchy_add(hier, anum, 0U, va_arg(ap,
const char*));
5088 va_arg(ap,
const char*));
5093 res = hierarchy_update(hier, anum, va_arg(ap,
const char*));
5125 const char* overview)
5127 static const char mime_v_field[] =
"MIME-Version: 1.0\r\n";
5128 static const char newsgroups_field[] =
"Newsgroups: ";
5130 static const char* field[] =
5132 "",
"Subject: ",
"From: ",
"Date: ",
"Message-ID: ",
"References: ",
5138 char* header = NULL;
5147 unsigned int f_max = 7;
5155 if(!rv && (
size_t) 7 < tmp && API_POSIX_UINT_MAX > tmp)
5162 header = (
char*) api_posix_malloc(hlen);
5164 len = strlen(overview);
5165 content = (
char*) api_posix_malloc(++len);
5167 while(NULL != header && NULL != content)
5170 strcpy(header, mime_v_field);
5171 hi =
sizeof(mime_v_field) - (
size_t) 1;
5175 rv = api_posix_snprintf(&header[hi], hlen - hi,
"%s%s\r\n",
5176 newsgroups_field, group->
name);
5179 if(hlen - hi > (
size_t) rv) { hi += (size_t) rv; }
5183 rv = sscanf(&overview[i],
"%s", content);
5193 for(f = 1; f_max >= f; ++f)
5196 p = strchr(&overview[i], 0x09);
5203 i += (size_t) (p - &overview[i]) + (size_t) 1;
5205 if(6U == f || (7U < f && f_max != f)) {
continue; }
5207 if(0x09 == (
int) (
unsigned char) overview[i]) {
continue; }
5208 rv = sscanf(&overview[i],
"%[^\t]", content);
5215 len = strlen(field[f]) + strlen(content) + (size_t) 3;
5216 while(hlen - hi < len)
5218 q = (
char*) api_posix_realloc(header, hlen *= (
size_t) 2);
5219 if(NULL == q) { error = 1;
break; }
5220 else { header = q; }
5225 rv = api_posix_snprintf(&header[hi], hlen - hi,
"%s%s\r\n",
5231 rv = api_posix_snprintf(&header[hi], hlen - hi,
"%s\r\n",
5236 if(hlen - hi <= (
size_t) rv)
5239 " parser detected (Bug)");
5252 printf(
"Pseudo-Header generated from overview:\n---\n%s---\n",
5257 if(0 > rv) { error = 1; }
5267 p = strchr(&overview[i], 0x0A);
5268 if(NULL == p) {
break; }
5269 i += (size_t) (p - &overview[i]) + (size_t) 1;
5276 if(NULL == header || NULL == content)
5278 PRINT_ERROR(
"Out of memory while processing header overview data");
5280 api_posix_free((
void*) header);
5281 api_posix_free((
void*) content);
5306 const char* res = NULL;
5314 for(i = 0; i < len; ++i)
5316 if(i && (
char) 0x0A == entity[i])
5318 if((
char) 0x0D == entity[i - (
size_t) 1])
5321 if((
size_t) 1 == i) { sob = ++i;
break; }
5322 else if((
size_t) 3 <= i)
5324 if((
char) 0x0A == entity[i - (
size_t) 2]
5325 && (
char) 0x0D == entity[i - (
size_t) 3])
5334 if((
size_t) 2 <= sob)
5338 h_len = sob - (size_t) 2;
5339 h = (
char*) api_posix_malloc(h_len + (
size_t) 1);
5343 strncpy(h, entity, h_len); h[h_len] = 0;
5351 rv = header_object_constructor(e_h, h);
5352 if(rv) { res = NULL; }
5354 api_posix_free((
void*) h);
5368 header_object_destructor(ehp);
5386 const char* buf = NULL;
5392 api_posix_free((
void*) buf);
5422 const char* name = CFG_NAME;
5423 char date[17] = { 0 };
5424 api_posix_time_t ts;
5425 api_posix_struct_tm t_data;
5426 api_posix_struct_tm* t = NULL;
5432 api_posix_time(&ts);
5433 t = api_posix_gmtime_r(&ts, &t_data);
5437 rv = api_posix_snprintf(date, (
size_t) 17,
5438 "%04d%02d%02dT%02d%02d%02dZ",
5439 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
5440 t->tm_hour, t->tm_min, t->tm_sec);
5443 PRINT_ERROR(
"Created date and time string is invalid (bug)");
5447 len += strlen(path);
5449 len += strlen(name);
5451 len += strlen(date);
5452 buf = (
char*) api_posix_malloc(len);
5495 static const char* months[12] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
5496 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec" };
5497 static const char* weekday[7] = {
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
5501 api_posix_time_t ts;
5502 api_posix_struct_tm t_data;
5503 api_posix_struct_tm* t = NULL;
5504 char t_zone[6] = { 0, 0, 0, 0, 0, 0 };
5516 buf = (
char*) api_posix_malloc(len);
5519 api_posix_time(&ts);
5520 #if CFG_USE_POSIX_API >= 200112
5523 t = api_posix_localtime_r(&ts, &t_data);
5527 if(api_posix_strftime(t_zone, 6,
"%z", t)) { fallback = 0; }
5534 t = api_posix_gmtime_r(&ts, &t_data);
5535 if(NULL == t) { error = 1; }
5536 else { strcpy(t_zone,
"-0000"); }
5540 rv = api_posix_snprintf(buf, len,
"%s, %d %s %04d %02d:%02d:%02d %s",
5541 weekday[t->tm_wday],
5542 t->tm_mday, months[t->tm_mon],
5544 t->tm_hour, t->tm_min, t->tm_sec, t_zone);
5545 if(!(30 <= rv && 31 >= rv))
5547 PRINT_ERROR(
"Created date and time string is invalid (bug)");
5552 #if CFG_USE_XSI || CFG_USE_POSIX_API >= 200112
5559 if(!api_posix_strftime(t_zone, 6,
"%Z", t))
5561 PRINT_ERROR(
"Creating timezone name comment failed");
5566 strcat(buf, t_zone);
5577 api_posix_free((
void*) buf);
5640 const char datext[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
5641 "0123456789" "!#$%&'*+-/=?^_`{|}~" ".";
5644 api_posix_time_t ts;
5646 unsigned long int r;
5647 unsigned long int pid;
5650 unsigned char secs[6];
5651 unsigned char rpp[6];
5652 const char* buf_date = NULL;
5653 const char* buf_rpp = NULL;
5657 if(NULL == fqdn) { error = 1; }
5661 if(!len) { error = 1; }
5663 else if( len != strspn(fqdn, datext)
5665 ||
'.' == fqdn[len - (
size_t) 1] )
5667 PRINT_ERROR(
"Invalid FQDN format (dot-atom syntax required)");
5681 len += strlen(CFG_NAME);
5683 len += strlen(fqdn);
5686 if((
size_t) 251 < len)
5688 PRINT_ERROR(
"Invalid message ID (FQDN too long)");
5695 api_posix_time(&ts);
5699 secs[2] = (
unsigned char) (ts_int >> 24);
5700 secs[3] = (
unsigned char) (ts_int >> 16);
5701 secs[4] = (
unsigned char) (ts_int >> 8);
5702 secs[5] = (
unsigned char) (ts_int & 0xFFU);
5704 if(rv) { error = 1; }
5709 r = (
unsigned long int) api_posix_random();
5710 rpp[0] = (
unsigned char) (r >> 8);
5711 rpp[1] = (
unsigned char) (r & 0xFFU);
5712 pid = (
unsigned long int) api_posix_getpid();
5713 rpp[2] = (
unsigned char) (pid >> 24);
5714 rpp[3] = (
unsigned char) (pid >> 16);
5715 rpp[4] = (
unsigned char) (pid >> 8);
5716 rpp[5] = (
unsigned char) (pid & 0xFFU);
5718 if(rv) { error = 1; }
5723 buf = (
char*) api_posix_malloc(len);
5728 strcat(buf, buf_date);
5729 strcat(buf, buf_rpp);
5730 strcat(buf,
".A3." CFG_NAME
"@");
5739 for(i = 0; len > i; ++i)
5741 if(
'@' == buf[i]) {
break; }
5742 if(
'/' == buf[i]) { buf[i] =
'-'; }
5747 fprintf(stderr,
"%s: %sFunction core_get_msgid() returned error\n",
5775 const char* confdir = NULL;
5776 const char* spn = NULL;
5778 const char* scheme_string = NULL;
5779 const char* sec = NULL;
5783 const char* mac_enc;
5792 scheme_string =
"sha1:";
5798 scheme_string =
"sha256:";
5803 PRINT_ERROR(
"Scheme requested for Cancel-Key not supported");
5808 if(NULL != scheme_string)
5822 rv =
hmac_sha1_160(msgid, strlen(msgid), sec, strlen(sec), mac);
5834 (api_posix_mode_t) API_POSIX_S_IRWXU);
5843 printf(
"%s: %sCL secret file: %s\n",
5849 api_posix_free((
void*) spn); spn = NULL;
5868 printf(
"%s: %sSize of CL secret: %u"
5870 (
unsigned int) len);
5872 if((
size_t) 32 > len)
5875 "SHA256 too short");
5900 len = strlen(scheme_string);
5901 len += strlen(mac_enc);
5902 res = (
char*) api_posix_malloc(++len);
5905 strcpy(res, scheme_string);
5906 strcat(res, mac_enc);
5937 const char* scheme_string = NULL;
5938 const char* ckey = NULL;
5939 const char* key = NULL;
5951 scheme_string =
"sha1:";
5957 scheme_string =
"sha256:";
5962 PRINT_ERROR(
"Scheme requested for Cancel-Lock not supported");
5967 if(NULL != scheme_string)
5972 len = strlen(scheme_string);
5974 if(strlen(ckey) < len || strncmp(ckey, scheme_string, len))
5976 PRINT_ERROR(
"Cancel-Key has unsupported scheme (bug)");
5978 else { key = &ckey[len]; }
6005 len += strlen(md_enc);
6006 res = (
char*) api_posix_malloc(++len);
6009 strcpy(res, scheme_string);
6010 strcat(res, md_enc);
6018 api_posix_free((
void*) ckey);
6047 const char* homedir = NULL;
6048 const char sigdir[] =
"/";
6049 char* sigpathname = NULL;
6050 const char* sigfile = NULL;
6054 unsigned int warn_flags = 0;
6076 sigpathname = (
char*) api_posix_malloc(strlen(homedir)
6080 if(NULL == sigpathname)
6083 "Cannot allocate memory for config file pathname");
6087 strcpy(sigpathname, homedir);
6088 strcat(sigpathname, sigdir);
6089 strcat(sigpathname, sigfile);
6096 rv =
fu_open_file(sigpathname, &fd, API_POSIX_O_RDONLY, 0);
6100 if(rv) { res = NULL; }
6107 api_posix_free((
void*) sigpathname);
6108 api_posix_free((
void*) homedir);
6110 else {
PRINT_ERROR(
"Environment variable 'HOME' is not defined"); }
6116 if(strncmp(res,
"-- \n", (
size_t) 4))
6126 if(len) { lines = 1; }
6127 for(i = 0; i < len; ++i)
6131 if(i + (
size_t) 1 != len)
6133 if(API_POSIX_SIZE_MAX > lines) { ++lines; }
6139 *warnings = warn_flags;
6171 const char* c1 = NULL;
6172 const char* c2 = NULL;
6177 res = (
char*) api_posix_malloc((
size_t) 998);
6182 fmt = (
char*) api_posix_malloc(strlen(cfg) + (size_t) 1);
6183 if (NULL == fmt) { error = 1; }
6187 p = strchr(fmt, (
int)
'%');
6191 if(
's' == p[1]) { c1 = ca; }
6192 else if(
'g' == p[1]) { p[1] =
's'; c1 = ngl; }
6196 p = strchr(&p[2], (
int)
'%');
6200 if(
's' == p[1]) { c2 = ca; }
6201 else if(
'g' == p[1]) { p[1] =
's'; c2 = ngl; }
6205 if(NULL != strchr(&p[2], (
int)
'%'))
6207 fprintf(stderr,
"%s: %s"
6208 "More than 2 conversions in introduction line "
6215 fprintf(stderr,
"%s: %s"
6216 "Conversion type in introduction line not "
6225 len = api_posix_snprintf(res, 998, fmt, c1, c2);
6226 if(0 >= len) { error = 1; }
6228 api_posix_free((
void*) fmt);
6233 api_posix_free((
void*) res);
6265 size_t len = strlen(pathname) + (size_t) 1;
6271 res = (
char*) api_posix_malloc(len);
6276 case FILTER_CS_UTF_8:
6280 if(NULL == rv) { error = 1; }
6283 if(len <= strlen(rv)) { error = 1; }
6284 else { strcpy(res, rv); }
6285 if(rv != pathname) {
enc_free((
void*) rv); }
6289 case FILTER_CS_ISO8859_1:
6293 if(NULL == rv) { error = 1; }
6298 if(NULL == rv2) { error = 1; }
6305 else { strcpy(res, rv2); }
6306 if(rv2 != rv) {
enc_free((
void*) rv2); }
6308 if(rv != pathname) {
enc_free((
void*) rv); }
6312 case FILTER_CS_ASCII:
6315 else { strcpy(res, pathname); }
6330 PRINT_ERROR(
"Pathname conversion to codeset of locale failed");
6331 api_posix_free((
void*) res);
6386 int flags = API_POSIX_O_WRONLY | API_POSIX_O_CREAT | API_POSIX_O_TRUNC;
6387 api_posix_mode_t perm = API_POSIX_S_IRUSR | API_POSIX_S_IWUSR |
6388 API_POSIX_S_IRGRP | API_POSIX_S_IWGRP |
6389 API_POSIX_S_IROTH | API_POSIX_S_IWOTH;
6400 if(!res) { fprintf(fs,
"%s", s); }
6429 #define CORE_PID_MAXLEN (size_t) 32
6430 char* tmppathname = NULL;
6433 const char* tmpdir = NULL;
6436 long int len_pn_max;
6439 char pid_string[CORE_PID_MAXLEN];
6448 len = strlen(tmpdir);
6449 pn = api_posix_malloc(++len);
6450 if(NULL != pn) { strcpy(pn, tmpdir); }
6451 if(0 <= rv) { api_posix_free((
void*) tmpdir); }
6456 len_pn = strlen(pn);
6457 len_pn_max = api_posix_pathconf(pn, API_POSIX_PC_NAME_MAX);
6461 PRINT_ERROR(
"Temporary file pathname length check failed");
6465 if(API_POSIX_LONG_MAX > len_pn_max)
6471 len = strlen(CFG_NAME);
6473 pid = (
long int) api_posix_getpid();
6474 rv = api_posix_snprintf(pid_string, CORE_PID_MAXLEN,
"%ld", pid);
6475 if(0 > rv || CORE_PID_MAXLEN <= (
size_t) rv) { error = 1; }
6480 if((
size_t) len_pn_max >= len)
6484 tmppathname = api_posix_realloc((
void*) pn, ++len_pn);
6485 if(NULL == tmppathname) { error = 1; }
6488 strcat(tmppathname,
"/" CFG_NAME
"_");
6489 strcat(tmppathname, pid_string);
6490 strcat(tmppathname,
"_XXXXXX");
6499 " (truncated and no longer unique)");
6501 tmppathname = api_posix_realloc((
void*) pn, ++len_pn);
6502 if(NULL == tmppathname)
6504 api_posix_free((
void*) pn);
6508 strncat(tmppathname,
"/" CFG_NAME, (
size_t) 8);
6509 strcat(tmppathname,
"_XXXXXX");
6515 if(NULL != tmppathname)
6517 rv = api_posix_mkstemp(tmppathname);
6521 api_posix_free((
void*) tmppathname);
6527 return(tmppathname);
6544 if(NULL != pathname)
6547 api_posix_free((
void*) pathname);
6560 n->nntp_state = CORE_NEXUS_CLOSED;
6578 rv = api_posix_pthread_mutex_lock(&pt_mutex);
6594 rv = api_posix_pthread_mutex_unlock(&pt_mutex);
6615 rv = api_posix_pthread_equal(ui_pt, api_posix_pthread_self());
6616 if(rv) { res = 1; }
else { res = 0; }
6656 api_posix_sigset_t sigmask;
6657 api_posix_sigset_t oldmask;
6660 ui_pt = api_posix_pthread_self();
6663 api_posix_sigemptyset(&sigmask);
6664 api_posix_sigaddset(&sigmask, API_POSIX_SIGINT);
6665 api_posix_sigaddset(&sigmask, API_POSIX_SIGQUIT);
6666 api_posix_sigaddset(&sigmask, API_POSIX_SIGTERM);
6667 res = api_posix_pthread_sigmask(API_POSIX_SIG_BLOCK, &sigmask, &oldmask);
6668 if(res) {
PRINT_ERROR(
"Setting signal mask failed"); }
6680 api_posix_srandom((
unsigned int) api_posix_getpid());
6682 res = api_posix_pthread_create(&pt, NULL, core_main, NULL);
6683 if(res) {
PRINT_ERROR(
"Spawning thread failed"); }
6688 res = api_posix_pthread_sigmask(API_POSIX_SIG_SETMASK, &oldmask, NULL);
6721 printf(
"%s: %sWait for command queue to drain\n",
6724 rv = commands_in_queue(10U, 100U);
6725 if(rv) {
PRINT_ERROR(
"Command queue drain timeout"); }
6733 command = CORE_TERMINATE_NEXUS;
6734 rv = api_posix_pthread_cond_signal(&pt_cond);
6735 if(rv) {
PRINT_ERROR(
"Waking up core thread failed"); }
6739 rv = commands_in_queue(10U, 100U);
6740 if(rv) {
PRINT_ERROR(
"Nexus termination failed"); }
6747 rv = api_posix_pthread_cancel(pt);
6748 if(rv) {
PRINT_ERROR(
"Cancelling core thread failed"); }
6756 rv = api_posix_pthread_join(pt, NULL);
6757 if(rv) {
PRINT_ERROR(
"Joining core thread failed"); }
6763 hierarchy_element_destructor(&h);