diff --git a/checkin_notes b/checkin_notes index 99ba1ffcd4..9c1340b572 100644 --- a/checkin_notes +++ b/checkin_notes @@ -365,3 +365,13 @@ David 12 Jan 2010 sched handle_request.cpp sched_types.cpp,h + +David 12 Jan 2010 + - Notices: put message bodies inside CDATA + - XML_PARSER: handle CDATA + + client/ + cs_notice.cpp,h + lib/ + notice.cpp + parse.cpp,h diff --git a/client/cs_notice.cpp b/client/cs_notice.cpp index be9bab1f23..6f9ba20e6c 100644 --- a/client/cs_notice.cpp +++ b/client/cs_notice.cpp @@ -335,15 +335,14 @@ void NOTICES::prune() { } } -// write archive file for the RSS feed specified by URL -// (or, if blank, non-RSS notices) +// write archive file for the given RSS feed +// (or, if NULL, non-RSS notices) // -void NOTICES::write_archive(char* url) { - char buf[256], path[256]; +void NOTICES::write_archive(RSS_FEED* rfp) { + char path[256]; - if (url) { - escape_project_url(url, buf); - sprintf(path, NOTICES_DIR"/archive_%s", buf); + if (rfp) { + rfp->archive_file_name(path); } else { strcpy(path, NOTICES_DIR"/archive.xml"); } @@ -355,8 +354,8 @@ void NOTICES::write_archive(char* url) { if (!f) return; for (unsigned int i=0; iurl, n.feed_url)) continue; } else { if (strlen(n.feed_url)) continue; } @@ -388,13 +387,13 @@ void NOTICES::write(int seqno, MIOFILE& fout, bool public_only) { void RSS_FEED::feed_file_name(char* path) { char buf[256]; - escape_project_url(url, buf); + escape_project_url(url_base, buf); sprintf(path, NOTICES_DIR"/%s", buf); } void RSS_FEED::archive_file_name(char* path) { char buf[256]; - escape_project_url(url, buf); + escape_project_url(url_base, buf); sprintf(path, NOTICES_DIR"/archive_%s", buf); } @@ -428,6 +427,9 @@ int RSS_FEED::parse_desc(XML_PARSER& xp) { } return ERR_XML_PARSE; } + strcpy(url_base, url); + char* p = strchr(url_base, '?'); + if (p) *p = 0; return 0; } if (xp.parse_str(tag, "url", url, sizeof(url))) continue; @@ -462,15 +464,25 @@ int RSS_FEED::parse_items(XML_PARSER& xp, int& nitems) { char tag[256]; bool is_tag; nitems = 0; + int ntotal = 0, nerror = 0; while (!xp.get(tag, sizeof(tag), is_tag)) { if (!is_tag) continue; if (!strcmp(tag, "/rss")) { + if (log_flags.notice_debug) { + msg_printf(0, MSG_INFO, + "[notice_debug] parsed RSS feed: total %d error %d added %d", + ntotal, nerror, nitems + ); + } return 0; } if (!strcmp(tag, "item")) { NOTICE n; + ntotal++; int retval = n.parse_rss(xp); - if (!retval) { + if (retval) { + nerror++; + } else { n.arrival_time = gstate.now; strcpy(n.feed_url, url); if (notices.append_unique(n)) { @@ -559,7 +571,7 @@ void RSS_FEED_OP::handle_reply(int http_op_retval) { fclose(f); if (nitems) { - notices.write_archive(rfp->url); + notices.write_archive(rfp); } } diff --git a/client/cs_notice.h b/client/cs_notice.h index 4362727776..d8c9d93f1a 100644 --- a/client/cs_notice.h +++ b/client/cs_notice.h @@ -73,7 +73,7 @@ struct NOTICES { void init(); void init_rss(); int read_archive_file(char* file, char* feed_url); - void write_archive(char* url); + void write_archive(struct RSS_FEED*); void prune(); }; @@ -81,6 +81,7 @@ extern NOTICES notices; struct RSS_FEED { char url[256]; + char url_base[256]; double poll_interval; double next_poll_time; bool use_seqno; diff --git a/lib/notice.cpp b/lib/notice.cpp index b50eb6029c..4b2057a8c4 100644 --- a/lib/notice.cpp +++ b/lib/notice.cpp @@ -67,7 +67,7 @@ void NOTICE::write(MIOFILE& f, bool for_gui) { f.printf( "\n" " %s\n" - " %s\n" + " \n" " %f\n" " %f\n" " %d\n" diff --git a/lib/parse.cpp b/lib/parse.cpp index db7d8859dd..a98b9c7cf4 100644 --- a/lib/parse.cpp +++ b/lib/parse.cpp @@ -464,16 +464,20 @@ bool XML_PARSER::scan_nonws(int& first_char) { } } +#define XML_PARSE_COMMENT 1 +#define XML_PARSE_EOF 2 +#define XML_PARSE_CDATA 3 + int XML_PARSER::scan_comment() { char buf[256]; char* p = buf; while (1) { int c = f->_getc(); - if (c == EOF) return 2; + if (c == EOF) return XML_PARSE_EOF; *p++ = c; *p = 0; if (strstr(buf, "-->")) { - return 1; + return XML_PARSE_COMMENT; } if (strlen(buf) > 32) { strcpy(buf, buf+16); @@ -482,6 +486,27 @@ int XML_PARSER::scan_comment() { } } +int XML_PARSER::scan_cdata(char* buf, int len) { + char* p = buf; + len--; + while (1) { + int c = f->_getc(); + if (c == EOF) return XML_PARSE_EOF; + if (len) { + *p++ = c; + len--; + } + if (c == '>') { + *p = 0; + char* q = strstr(buf, "]]>"); + if (q) { + *q = 0; + return XML_PARSE_CDATA; + } + } + } +} + // we just read a <; read until we find a >. // Given : // - copy tag (or tag/) to tag_buf @@ -493,11 +518,13 @@ int XML_PARSER::scan_comment() { // 2 if reached EOF // int XML_PARSER::scan_tag( - char* tag_buf, int tag_len, char* attr_buf, int attr_len + char* tag_buf, int _tag_len, char* attr_buf, int attr_len ) { int c; char* buf_start = tag_buf; bool found_space = false; + int tag_len = _tag_len; + for (int i=0; ; i++) { c = f->_getc(); if (c == EOF) return 2; @@ -536,6 +563,9 @@ int XML_PARSER::scan_tag( if (i==2 && !strncmp(buf_start, "!--", 3)) { return scan_comment(); } + if (i==7 && !strncmp(buf_start, "![CDATA[", 8)) { + return scan_cdata(buf_start, tag_len); + } } } @@ -572,9 +602,13 @@ bool XML_PARSER::get(char* buf, int len, bool& is_tag, char* attr_buf, int attr_ if (eof) return true; if (c == '<') { int retval = scan_tag(buf, len, attr_buf, attr_len); - if (retval == 2) return true; - if (retval == 1) continue; - is_tag = true; + if (retval == XML_PARSE_EOF) return true; + if (retval == XML_PARSE_COMMENT) continue; + if (retval == XML_PARSE_CDATA) { + is_tag = false; + } else { + is_tag = true; + } } else { buf[0] = c; eof = copy_until_tag(buf+1, len-1); diff --git a/lib/parse.h b/lib/parse.h index a60564b280..340c6aa495 100644 --- a/lib/parse.h +++ b/lib/parse.h @@ -29,6 +29,7 @@ class XML_PARSER { bool scan_nonws(int&); int scan_comment(); int scan_tag(char*, int, char* ab=0, int al=0); + int scan_cdata(char*, int); bool copy_until_tag(char*, int); public: MIOFILE* f;