PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/NewsCache-1.2rc6/NServer-0.9.1/Article.cc

#
C++ | 375 lines | 309 code | 39 blank | 27 comment | 151 complexity | 1998a65d68db36a5936853297822aa4c MD5 | raw file
Possible License(s): GPL-2.0
  1. /* Copyright (C) 2003 Herbert Straub
  2. * Original Author (Article.h) Thomas Gschwind
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. #include "Article.h"
  19. #ifdef HAVE_SSTREAM
  20. #include <sstream>
  21. #else
  22. #include <strstream>
  23. #endif
  24. using namespace std;
  25. InvalidArticleError::InvalidArticleError(const char *txt, const char *file,
  26. const char *function, int line):NSError(txt,
  27. file,
  28. function,
  29. line)
  30. {
  31. }
  32. InvalidArticleError::InvalidArticleError(const string & txt, const char *file,
  33. const char *function, int line):NSError(txt,
  34. file,
  35. function,
  36. line)
  37. {
  38. }
  39. void InvalidArticleError::print(void)
  40. {
  41. slog << "Exception!\n"
  42. << " Type: InvalidArticle\n"
  43. << " Desc: " << _errtext << "\n";
  44. }
  45. Article::Article()
  46. {
  47. }
  48. Article::Article(Article * a)
  49. //: _nbr(a->getnbr()), _text(a->GetText()), _ctext(_text.c_str())
  50. {
  51. _nbr = a->getnbr();
  52. _text = a->GetText();
  53. _ctext = _text.c_str();
  54. }
  55. Article::Article(int artnbr)
  56. {
  57. setnbr(artnbr);
  58. }
  59. Article::Article(int artnbr, const char *text, int textlen)
  60. //: setnbr(artnbr), _text.assign(text, textlen), _ctext = _text.c_str()
  61. {
  62. setnbr(artnbr);
  63. _text.assign(text, textlen);
  64. _ctext = _text.c_str();
  65. }
  66. Article::~Article ()
  67. {
  68. }
  69. void Article::read(std::istream & is)
  70. {
  71. DEBUG(slog.p(Logger::Debug) << "Article::read(&is)\n");
  72. _text = "";
  73. readtext(is, _text);
  74. _ctext = _text.c_str();
  75. }
  76. void Article::setnbr(int nbr)
  77. {
  78. _nbr = nbr;
  79. }
  80. void Article::clear(void)
  81. {
  82. _nbr = 0;
  83. _text = "";
  84. _ctext = _text.c_str();
  85. }
  86. void Article::settext(const std::string & text)
  87. {
  88. _text = text;
  89. _ctext = _text.c_str();
  90. }
  91. int Article::getnbr(void) const
  92. {
  93. return _nbr;
  94. }
  95. string Article::GetText (void)
  96. {
  97. return _text;
  98. }
  99. const char* Article::c_str(void)
  100. {
  101. return _ctext;
  102. }
  103. int Article::length(void) const
  104. {
  105. return _text.length();
  106. }
  107. int Article::has_field(const char *ifld)
  108. {
  109. char c;
  110. c = *find_field(ifld);
  111. if (!c || c == '\r' || c == '\n')
  112. return 0;
  113. return 1;
  114. }
  115. const char* Article::find_field(const char *ifld) const
  116. {
  117. char hdrbuf[513], *p;
  118. const char *q, *fld;
  119. const char *ifp;
  120. unsigned int i;
  121. i = 1;
  122. p = hdrbuf;
  123. ifp = ifld;
  124. while (i < sizeof(hdrbuf) && (*p = tolower(*ifp))) {
  125. i++;
  126. p++;
  127. ifp++;
  128. }
  129. if (i == sizeof(hdrbuf)) {
  130. p--;
  131. VERB(slog.
  132. p(Logger::
  133. Error) <<
  134. "Article::find_field: field exceeds 512 characters! Contact maintainer!\n");
  135. }
  136. *p = '\0';
  137. q = _ctext;
  138. for (;;) {
  139. p = hdrbuf;
  140. fld = q;
  141. while (*p && *p == tolower(*q)) {
  142. p++;
  143. q++;
  144. }
  145. if (*p == '\0')
  146. return fld;
  147. // bad luck find next line
  148. while (*q && *q != '\r' && *q != '\n')
  149. q++;
  150. if (!*q) {
  151. VERB(slog.
  152. p(Logger::
  153. Error) <<
  154. "Article::find_field: unterminated header, no body\n");
  155. throw
  156. InvalidArticleError
  157. ("unterminated header, no body",
  158. ERROR_LOCATION);
  159. }
  160. // Skip first CRLF
  161. if (*q == '\r' && *(q + 1) == '\n') {
  162. q += 2;
  163. } else if (*q == '\n') {
  164. ++q;
  165. } else {
  166. VERB(slog.
  167. p(Logger::
  168. Error) <<
  169. "Article::find_field: line not terminated with CRLF\n");
  170. throw
  171. InvalidArticleError
  172. ("line not terminated with CRLF/LF",
  173. ERROR_LOCATION);
  174. }
  175. if (*q == '\r' || *q == '\n')
  176. return q;
  177. }
  178. }
  179. string Article::getfield(const char *ifld, int Full) const
  180. {
  181. string rfld;
  182. const char *p, *fld;
  183. if (strcasecmp(ifld, "bytes:") == 0) {
  184. #ifdef HAVE_SSTREAM
  185. stringstream sb;
  186. #else
  187. strstream sb;
  188. #endif
  189. sb << _text.length();
  190. return sb.rdbuf()->str();
  191. }
  192. fld = find_field(ifld);
  193. if (*fld == '\r' || *fld == '\n') {
  194. // Bad luck, did not find the header
  195. throw NoSuchFieldError(ifld, ERROR_LOCATION);
  196. }
  197. // found header
  198. p = fld + strlen(ifld);
  199. while (*p == ' ' || *p == '\t')
  200. p++;
  201. if (!Full)
  202. fld = p;
  203. while (*p && *p != '\r' && *p != '\n')
  204. p++;
  205. rfld.assign(fld, p - fld);
  206. if (*p == '\n')
  207. p++;
  208. else if (*p == '\r') {
  209. if (*(p + 1) != '\n')
  210. throw
  211. InvalidArticleError
  212. ("illegaly terminated line, neither <lf> nor <cr><lf>",
  213. ERROR_LOCATION);
  214. p += 2;
  215. }
  216. if (!(*p))
  217. throw InvalidArticleError("article without body",
  218. ERROR_LOCATION);
  219. // multi-line header?
  220. while (*p == ' ' || *p == '\t') {
  221. do {
  222. p++;
  223. } while (*p == ' ' || *p == '\t');
  224. fld = p;
  225. while (*p && *p != '\r' && *p != '\n')
  226. p++;
  227. rfld.append(fld, p - fld);
  228. if (*p == '\n')
  229. p++;
  230. else if (*p == '\r') {
  231. if (*(p + 1) != '\n')
  232. throw
  233. InvalidArticleError
  234. ("illegaly terminated line, neither <lf> nor <cr><lf>",
  235. ERROR_LOCATION);
  236. p += 2;
  237. }
  238. if (!(*p))
  239. throw
  240. InvalidArticleError
  241. ("article without body", ERROR_LOCATION);
  242. }
  243. return rfld;
  244. }
  245. void Article::setfield(const char *ifld, const char *field_data)
  246. {
  247. const char *p, *fld;
  248. fld = find_field(ifld);
  249. if (*fld == '\r' || *fld == '\n') {
  250. // Bad luck, did not find the header
  251. _text.insert(fld - _ctext, field_data);
  252. _ctext = _text.c_str();
  253. return;
  254. }
  255. // We have found the header
  256. p = fld + strlen(ifld);
  257. while (isspace(*p))
  258. p++;
  259. while (*p && *p != '\r' && *p != '\n')
  260. p++;
  261. ASSERT(if (!(*p)) {
  262. slog.p(Logger::Error) << "Article without body.\n";}
  263. if (*p == '\r' && !(*(p + 1))) {
  264. slog.p(Logger::Error) << "Article ended with <CR><NULL>.\n";}
  265. );
  266. if (*p == '\n')
  267. p++;
  268. if (*p == '\r' && *(p + 1) == '\n')
  269. p += 2;
  270. // Multiline header?
  271. while (isspace(*p) && *p != '\n' && *p != '\r') {
  272. while (isspace(*p))
  273. p++;
  274. while (*p != '\r' && *p != '\n')
  275. p++;
  276. ASSERT(if (!(*p)) {
  277. slog.p(Logger::Error) << "Article without body.\n";}
  278. if (*p == '\r' && !(*(p + 1))) {
  279. slog.
  280. p(Logger::
  281. Error) << "Article ended with <CR><NULL>.\n";}
  282. );
  283. if (*p == '\n')
  284. p++;
  285. if (*p == '\r' && *(p + 1) == '\n')
  286. p += 2;
  287. }
  288. _text.replace(fld - _ctext, p - fld, field_data);
  289. _ctext = _text.c_str();
  290. }
  291. ostream & Article::write(ostream & os, int flags)
  292. {
  293. const char *p, *q;
  294. if ((flags & (Head | Body)) == (Head | Body)) {
  295. os << _text;
  296. return os;
  297. }
  298. p = q = _ctext;
  299. for (;;) {
  300. while (*q && *q != '\r' && *q != '\n')
  301. q++;
  302. if (!*q) {
  303. VERB(slog.
  304. p(Logger::
  305. Notice) <<
  306. "Article::write: Article without body!\n");
  307. break;
  308. }
  309. if (*q == '\r' && *(q + 1) == '\n'
  310. && *(q + 2) == '\r' && *(q + 3) == '\n') {
  311. q += 2;
  312. break;
  313. }
  314. if (*q == '\n' && *(q + 1) == '\n') {
  315. q++;
  316. break;
  317. }
  318. while (*q == '\n' || *q == '\r')
  319. q++;
  320. }
  321. if (flags & Head) {
  322. os.write(p, q - p);
  323. } else if (flags & Body) {
  324. if (*q == '\n')
  325. p++;
  326. else if (*q == '\r' && *(q + 1) == '\n')
  327. q += 2;
  328. os.write(q, _text.length() - (q - p));
  329. }
  330. return os;
  331. }
  332. ostream & operator <<(ostream & os, Article & art)
  333. {
  334. os << art._text;
  335. return os;
  336. }