PageRenderTime 58ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/suck-4.3.2/active.c

#
C | 543 lines | 428 code | 64 blank | 51 comment | 167 complexity | 7f5c8845e40939e76effaf19857cd12a MD5 | raw file
  1. #include <config.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <ctype.h>
  6. #ifdef HAVE_UNISTD_H
  7. #include <unistd.h>
  8. #endif
  9. #ifdef HAVE_REGEX_H
  10. #include <regex.h>
  11. #endif
  12. #ifdef DMALLOC
  13. #include <dmalloc.h>
  14. #endif
  15. #include "suck_config.h"
  16. #include "both.h"
  17. #include "suck.h"
  18. #include "phrases.h"
  19. #include "timer.h"
  20. #include "suckutils.h"
  21. #include "active.h"
  22. typedef struct Dactive {
  23. char *group;
  24. int high;
  25. int done; /* have we gotten the msgids ? */
  26. int postyn;
  27. struct Dactive *next;
  28. } Active, *Pactive;
  29. typedef struct Dignore {
  30. char *group;
  31. struct Dignore *next;
  32. #ifdef HAVE_REGEX_H
  33. regex_t match;
  34. int use_regex;
  35. #endif
  36. } Ignore, *Pignore;
  37. /* local function prototypes */
  38. int add_to_list(Pactive *, const char *, Pignore, int);
  39. int get_msgids(PMaster, Pactive);
  40. Pignore read_ignore(PMaster);
  41. void do_free(Pactive, Pignore);
  42. Pactive nntp_active(PMaster, Pignore);
  43. Pactive read_active(PMaster, Pignore);
  44. /*-------------------------------------------------------------------------*/
  45. int get_message_index_active(PMaster master) {
  46. int retval = RETVAL_OK;
  47. Pactive listhead = NULL;
  48. Pignore ignorehead = NULL;
  49. TimerFunc(TIMER_START, 0, NULL);
  50. /* first get our groups to ignore */
  51. ignorehead = read_ignore(master);
  52. /* Now try to get the active list */
  53. if(master->do_active == TRUE) {
  54. listhead = nntp_active(master, ignorehead);
  55. }
  56. if(listhead == NULL && master->activefile != NULL) {
  57. /* can we get active list from local file */
  58. listhead = read_active(master, ignorehead);
  59. }
  60. /* if it takes a while to read the active the other end */
  61. /* might have timed out, hence this option */
  62. if(master->conn_active == TRUE) {
  63. retval = do_connect(master, CONNECT_AGAIN);
  64. }
  65. /* now get the MsgIds */
  66. if(retval == RETVAL_OK && listhead != NULL) {
  67. retval = get_msgids(master, listhead);
  68. do_free(listhead, ignorehead);
  69. }
  70. else {
  71. retval = RETVAL_ERROR;
  72. }
  73. TimerFunc(TIMER_TIMEONLY, 0, master->msgs);
  74. if(retval == RETVAL_ERROR){
  75. retval = get_message_index(master);
  76. }
  77. else {
  78. print_phrases(master->msgs, active_phrases[5], str_int(master->nritems), NULL);
  79. }
  80. return retval;
  81. }
  82. /*------------------------------------------------------------------------*/
  83. Pactive nntp_active(PMaster master, Pignore ignorehead) {
  84. int localfd, nr;
  85. char *resp;
  86. Pactive listhead = NULL;
  87. int retval = RETVAL_OK;
  88. /* get active file from nntp host */
  89. if((localfd = connect_local(master)) < 0 ) {
  90. error_log(ERRLOG_REPORT, active_phrases[0], NULL);
  91. }
  92. else {
  93. /* now get the list of groups */
  94. print_phrases(master->msgs, active_phrases[2], master->localhost, NULL);
  95. if(master->debug == TRUE) {
  96. do_debug("Sending command: LIST\n");
  97. }
  98. sputline(localfd, "LIST\r\n", master->local_ssl, master->local_ssl_struct);
  99. if(sgetline(localfd, &resp, master->local_ssl, master->local_ssl_struct) >= 0) {
  100. if(master->debug == TRUE) {
  101. do_debug("got answer: %s", resp);
  102. }
  103. number(resp, &nr);
  104. if(nr == 215) { /* now we can get the list */
  105. do {
  106. if(sgetline(localfd, &resp, master->local_ssl, master->local_ssl_struct) > 0) {
  107. if(master->debug == TRUE) {
  108. do_debug("Got groupline: %s", resp);
  109. }
  110. if(resp[0] != '.' ) {
  111. retval = add_to_list(&listhead, resp, ignorehead,master->debug);
  112. }
  113. }
  114. else {
  115. retval = RETVAL_ERROR;
  116. }
  117. }
  118. while(resp[0] != '.' && retval == RETVAL_OK);
  119. if(retval != RETVAL_OK) {
  120. do_free(listhead, NULL);
  121. listhead = NULL;
  122. }
  123. }
  124. }
  125. disconnect_from_nntphost(localfd, master->local_ssl, &master->ssl_struct);
  126. }
  127. return listhead;
  128. }
  129. /*------------------------------------------------------------------------*/
  130. Pactive read_active(PMaster master, Pignore ignorehead) {
  131. /* read active list from file */
  132. Pactive listhead = NULL;
  133. FILE *fpi;
  134. char linein[MAXLINLEN];
  135. int retval = RETVAL_OK;
  136. if(master->debug == TRUE) {
  137. do_debug("Opening Active file: %s\n", master->activefile);
  138. }
  139. if((fpi = fopen(master->activefile, "r")) == NULL) {
  140. error_log(ERRLOG_REPORT, active_phrases[11], master->activefile, NULL);
  141. }
  142. else {
  143. while(fgets(linein, MAXLINLEN, fpi) != NULL && retval == RETVAL_OK) {
  144. if(master->debug == TRUE) {
  145. do_debug("Got line: %s", linein);
  146. }
  147. retval = add_to_list(&listhead, linein, ignorehead, master->debug);
  148. }
  149. fclose(fpi);
  150. if(retval != RETVAL_OK) {
  151. do_free(listhead, NULL);
  152. listhead = NULL;
  153. }
  154. }
  155. return listhead;
  156. }
  157. /*------------------------------------------------------------------------*/
  158. int connect_local(PMaster master) {
  159. /* connect to localhost NNTP server */
  160. int fd;
  161. char *inbuf;
  162. unsigned int port;
  163. port = (master->local_ssl == TRUE) ? LOCAL_SSL_PORT : LOCAL_PORT;
  164. if(master->debug == TRUE) {
  165. do_debug("Connecting to %s on port %d\n", master->localhost, port);
  166. }
  167. if((fd = connect_to_nntphost(master->localhost, NULL, 0, NULL, port, master->local_ssl, &master->local_ssl_struct)) >= 0) {
  168. /* get the announcement line */
  169. if(sgetline(fd, &inbuf, master->local_ssl, master->local_ssl_struct) < 0) {
  170. close(fd);
  171. fd = -1;
  172. }
  173. else if(master->debug == TRUE) {
  174. do_debug("Got: %s", inbuf);
  175. }
  176. }
  177. return fd;
  178. }
  179. /*----------------------------------------------------------------------------*/
  180. int add_to_list(Pactive *head, const char *groupline, Pignore ignorehead, int debug) {
  181. /* add one group to group list */
  182. Pactive temp, tptr;
  183. Pignore pignore;
  184. int len, retval= RETVAL_OK;
  185. char postyn;
  186. #ifdef HAVE_REGEX_H
  187. int reg_match;
  188. #endif
  189. len = 0;
  190. /* get length of group name */
  191. while(groupline[len] != ' ' && groupline[len] != '\0') {
  192. len++;
  193. }
  194. if((temp = malloc(sizeof(Active))) == NULL) {
  195. error_log(ERRLOG_REPORT, active_phrases[1], NULL);
  196. retval = RETVAL_ERROR;
  197. }
  198. else if((temp->group = malloc(len+1)) == NULL) {
  199. error_log(ERRLOG_REPORT, active_phrases[1], NULL);
  200. retval = RETVAL_ERROR;
  201. }
  202. else {
  203. /* now initialize the sucker and add it to the list*/
  204. temp->next = NULL;
  205. temp->high = 0;
  206. temp->done = FALSE;
  207. strncpy(temp->group, groupline, len);
  208. temp->group[len] = '\0'; /* NULL terminate it */
  209. sscanf(groupline, "%*s%*ld%*ld%c", &postyn);
  210. temp->postyn = (postyn == 'n') ? FALSE : TRUE;
  211. /* now check to see if we ignore this group, if so, don't add to list */
  212. /* we have to wait until here, because only now do we have the group */
  213. /* name in a separate field we can compare to the ignore list */
  214. pignore = ignorehead;
  215. #ifndef HAVE_REGEX_H
  216. while(pignore != NULL && strcmp(pignore->group, temp->group) != 0) {
  217. pignore = pignore->next;
  218. }
  219. #else
  220. reg_match = FALSE;
  221. while(pignore != NULL && reg_match == FALSE) {
  222. if(pignore->use_regex == FALSE) {
  223. if(strcmp(pignore->group, temp->group) == 0) {
  224. reg_match = TRUE;
  225. }
  226. else {
  227. pignore = pignore->next;
  228. }
  229. }
  230. else {
  231. if(regexec(&(pignore->match),temp->group, 0, NULL, 0) == 0) {
  232. reg_match = TRUE;
  233. }
  234. else {
  235. pignore = pignore->next;
  236. }
  237. }
  238. }
  239. #endif
  240. if(debug == TRUE ) {
  241. if(pignore == NULL) {
  242. do_debug("Adding to active list - %s\n",temp->group);
  243. }
  244. else {
  245. do_debug("Ignoring Group %s - match on %s\n",temp->group, pignore->group);
  246. }
  247. }
  248. if(pignore == NULL) {
  249. /* we didn't match, add to list */
  250. if(*head == NULL) {
  251. /* head node */
  252. *head = temp;
  253. }
  254. else {
  255. /* find end of list */
  256. tptr = *head;
  257. while(tptr->next != NULL) {
  258. tptr = tptr->next;
  259. }
  260. tptr->next = temp;
  261. }
  262. }
  263. }
  264. return retval;
  265. }
  266. /*---------------------------------------------------------------------------------*/
  267. void do_free(Pactive head, Pignore ihead) {
  268. /* free both linked lists and any alloced strings */
  269. Pactive temp;
  270. Pignore itemp;
  271. while(head != NULL) {
  272. if(head->group != NULL) {
  273. free(head->group);
  274. }
  275. temp=head->next;
  276. free(head);
  277. head = temp;
  278. }
  279. while(ihead != NULL) {
  280. if(ihead->group != NULL) {
  281. free(ihead->group);
  282. }
  283. itemp = ihead->next;
  284. free(ihead);
  285. ihead = itemp;
  286. }
  287. }
  288. /*-------------------------------------------------------------------------------*/
  289. int get_msgids(PMaster master, Pactive head) {
  290. /* read in the sucknewsrc, check to see if group is in active list */
  291. /* then download msgids and write it out to the new.sucknewsrc */
  292. FILE *oldrc, *newrc;
  293. int retval = RETVAL_OK, nrread, maxread;
  294. long lastread;
  295. char buf[MAXLINLEN+1], group[512], *ptr;
  296. Pactive plist;
  297. oldrc = newrc = NULL;
  298. if((newrc = fopen(full_path(FP_GET, FP_TMPDIR, N_NEWRC), "w" )) == NULL) {
  299. MyPerror(full_path(FP_GET, FP_TMPDIR, N_NEWRC));
  300. retval = RETVAL_ERROR;
  301. }
  302. if((oldrc = fopen(full_path(FP_GET, FP_DATADIR, N_OLDRC), "r" )) == NULL) {
  303. /* this isn't actually an error, since we can create it */
  304. print_phrases(master->msgs, active_phrases[6], NULL);
  305. }
  306. else {
  307. print_phrases(master->msgs, active_phrases[9], NULL);
  308. while(retval == RETVAL_OK && fgets(buf, MAXLINLEN-1, oldrc) != NULL) {
  309. ptr = buf;
  310. if(*ptr == SUCKNEWSRC_COMMENT_CHAR) {
  311. /* skip any white space before newsgroup name */
  312. while(! isalpha(*ptr)) {
  313. ptr++;
  314. }
  315. }
  316. maxread = -1; /* just in case */
  317. nrread = sscanf(ptr, "%s %ld %d\n", group, &lastread, &maxread);
  318. if(nrread < 2 || nrread > 3) {
  319. /* totally ignore any bogus lines */
  320. print_phrases(master->msgs, active_phrases[3], buf, NULL);
  321. }
  322. else {
  323. /* now find if group is still in active or not */
  324. plist = head;
  325. while( plist != NULL && strcmp(plist->group, group) != 0) {
  326. plist = plist->next;
  327. }
  328. if(plist == NULL) {
  329. print_phrases(master->msgs, active_phrases[4], buf, NULL);
  330. }
  331. else {
  332. /* valid group, lets get em */
  333. if(plist->postyn == FALSE) {
  334. /* we can't post, comment the line out */
  335. fprintf(newrc, "# %s %ld", group, lastread);
  336. if(maxread >= 0) {
  337. fprintf(newrc, " %d", maxread);
  338. }
  339. fputc('\n', newrc);
  340. }
  341. else if(maxread == 0) {
  342. /* just rewrite the line */
  343. fprintf(newrc,"%s %ld %d\n", group, lastread, maxread);
  344. }
  345. else {
  346. retval = do_one_group(master, buf, group, newrc, lastread, maxread);
  347. plist->done = TRUE;
  348. }
  349. }
  350. }
  351. }
  352. /* this is in case we had to abort the above while loop (due to loss of pipe to server) */
  353. /* and we hadn't finished writing out the suck.newrc, this finishes it up. */
  354. if(retval != RETVAL_OK) {
  355. do {
  356. fputs(buf, newrc);
  357. }
  358. while(fgets(buf, MAXLINLEN-1, oldrc) != NULL);
  359. }
  360. fclose(oldrc);
  361. }
  362. if(retval == RETVAL_OK) {
  363. /* okay add any new groups from active that weren't already in sucknewsrc */
  364. plist = head;
  365. if(plist != NULL) {
  366. print_phrases(master->msgs, active_phrases[8], NULL);
  367. }
  368. while( plist != NULL) {
  369. if(plist->done == FALSE) {
  370. /* create a line for newsrc file */
  371. lastread = master->active_lastread;
  372. maxread = 0;
  373. sprintf(buf,"%s %ld\n", plist->group, lastread);
  374. print_phrases(master->msgs, active_phrases[10], plist->group, NULL);
  375. if(plist->postyn == FALSE) {
  376. /* we can't post, comment the line out */
  377. fprintf(newrc, "# %s", buf);
  378. }
  379. else {
  380. retval = do_one_group(master, buf, plist->group, newrc, lastread, maxread);
  381. plist->done = TRUE;
  382. }
  383. }
  384. plist = plist->next;
  385. }
  386. }
  387. if(newrc != NULL) {
  388. fclose(newrc);
  389. }
  390. return retval;
  391. }
  392. /*--------------------------------------------------------------------------------------------------*/
  393. Pignore read_ignore(PMaster master) {
  394. /* read in ignore file, and build list of groups to ignore */
  395. FILE *fpi;
  396. Pignore head, temp, last;
  397. char buf[MAXLINLEN+1], *ptr;
  398. int errflag = FALSE;
  399. #ifdef HAVE_REGEX_H
  400. int err;
  401. char errmsg[256];
  402. int i;
  403. #endif
  404. head = last = NULL;
  405. /* first check if one with postfix is present, if not, use non postfix version */
  406. fpi = fopen(full_path(FP_GET, FP_DATADIR, N_ACTIVE_IGNORE), "r");
  407. if(fpi == NULL) {
  408. fpi = fopen(full_path(FP_GET_NOPOSTFIX, FP_DATADIR, N_ACTIVE_IGNORE), "r");
  409. }
  410. if(fpi != NULL) {
  411. while(fgets(buf, MAXLINLEN, fpi) != NULL) {
  412. /* strip off any trailing spaces from group name */
  413. ptr = buf;
  414. while(!isspace(*ptr)) {
  415. ptr++;
  416. }
  417. *ptr = '\0';
  418. if((temp = malloc(sizeof(Ignore))) == NULL) {
  419. error_log(ERRLOG_REPORT, active_phrases[7], NULL);
  420. errflag = TRUE;
  421. }
  422. else if((temp->group = malloc(strlen(buf)+1)) == NULL) {
  423. error_log(ERRLOG_REPORT, active_phrases[7], NULL);
  424. errflag = TRUE;
  425. }
  426. else {
  427. if(master->debug == TRUE) {
  428. do_debug("Ignoring group %s\n", buf);
  429. }
  430. /* add to list */
  431. strcpy(temp->group, buf);
  432. temp->next = NULL;
  433. if(head == NULL) {
  434. head = temp;
  435. }
  436. else {
  437. last->next = temp;
  438. }
  439. last = temp;
  440. #ifdef HAVE_REGEX_H
  441. /* first add ^ and $ so that we don't match */
  442. /* partials unless they have wild cards */
  443. if(buf[0] != '^') {
  444. buf[0] = '^';
  445. strcpy(&buf[1], temp->group);
  446. }
  447. else {
  448. strcpy(buf,temp->group);
  449. }
  450. i = strlen(buf);
  451. if(buf[i-1] != '$') {
  452. buf[i] = '$';
  453. buf[i+1] = '\0';
  454. }
  455. /* now regcomp it for later comparision */
  456. temp->use_regex = TRUE;
  457. if((err = regcomp(&(temp->match), buf, REG_NOSUB | REG_ICASE | REG_EXTENDED)) != 0)
  458. {
  459. regerror(err, &(temp->match), errmsg, sizeof(errmsg));
  460. error_log(ERRLOG_REPORT, active_phrases[12], buf, errmsg, NULL);
  461. temp->use_regex = FALSE;
  462. }
  463. #endif
  464. }
  465. }
  466. fclose(fpi);
  467. }
  468. if(errflag == TRUE) {
  469. while(head != NULL) {
  470. if(head->group != NULL) {
  471. free(head->group);
  472. }
  473. temp = head->next;
  474. free(head);
  475. head = temp;
  476. }
  477. }
  478. return head;
  479. }