PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/2.3.0/Drivers/nn/nntp.c

#
C | 854 lines | 612 code | 214 blank | 28 comment | 114 complexity | de559eeec9857ef6728ffda12b48ed81 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-1.0
  1. /**
  2. Copyright (C) 1995, 1996 by Ke Jin <kejin@visigenic.com>
  3. Enhanced for unixODBC (1999) by Peter Harvey <pharvey@codebydesign.com>
  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. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. **/
  13. #include <config.h>
  14. #include <nnconfig.h>
  15. #include <string.h>
  16. #include <errno.h>
  17. #include <nntp.h>
  18. # include "nntp.ci"
  19. #ifndef WINSOCK
  20. # include <sys/types.h>
  21. # include <sys/socket.h>
  22. # include <netdb.h>
  23. # include <netinet/in.h>
  24. #else
  25. # include <winsock.h>
  26. #endif
  27. #include <nntp.h>
  28. typedef struct {
  29. long article_num;
  30. long data;
  31. } nntp_xhdridx_t;
  32. typedef struct {
  33. char* header;
  34. long start;
  35. long end;
  36. int count;
  37. nntp_xhdridx_t* idxs;
  38. char* buf;
  39. } nntp_xhdrinfo_t;
  40. typedef struct {
  41. void* sin;
  42. void* sout;
  43. int postok;
  44. int code;
  45. /* group info */
  46. long start;
  47. long end;
  48. int count;
  49. /* access mode */
  50. int mode;
  51. } nntp_cndes_t;
  52. void* nntp_connect( char* server )
  53. {
  54. int sock, err;
  55. char msgbuf[128];
  56. struct sockaddr_in
  57. srvaddr;
  58. nntp_cndes_t* cndes;
  59. #ifdef WINSOCK
  60. WSADATA winsock_data;
  61. # ifndef WINSOCKVERSION
  62. # define WINSOCKVERSION ( 0x0101 ) /* default version 1.1 */
  63. # endif
  64. if( WSAStartup((WORD)WINSOCKVERSION, &winsock_data) )
  65. return 0; /* fail to init winsock */
  66. #endif
  67. if( atoi(server) > 0 )
  68. /* an IP address */
  69. {
  70. srvaddr.sin_family = AF_INET;
  71. srvaddr.sin_addr.s_addr = inet_addr(server);
  72. }
  73. else
  74. /* a domain name */
  75. {
  76. struct hostent* ph;
  77. if( ! (ph = gethostbyname( server )) )
  78. return 0;
  79. srvaddr.sin_family = ph->h_addrtype;
  80. memcpy( (char*)&srvaddr.sin_addr,
  81. (char*)ph->h_addr, ph->h_length);
  82. }
  83. cndes = (nntp_cndes_t*)MEM_ALLOC(sizeof(nntp_cndes_t));
  84. if( ! cndes )
  85. return 0;
  86. srvaddr.sin_port = htons(119);
  87. if( (sock = socket( AF_INET, SOCK_STREAM, 0)) == -1 )
  88. {
  89. MEM_FREE(cndes);
  90. return 0;
  91. }
  92. if( connect( sock, (struct sockaddr*)&srvaddr, sizeof(srvaddr) ) == -1 )
  93. {
  94. SOCK_CLOSE( sock );
  95. MEM_FREE(cndes);
  96. return 0;
  97. }
  98. if( ! (cndes->sin = SOCK_FDOPEN( sock, "r")) )
  99. {
  100. SOCK_CLOSE( sock );
  101. MEM_FREE(cndes);
  102. return 0;
  103. }
  104. if( ! (cndes->sout = SOCK_FDOPEN( sock, "w")) )
  105. {
  106. SOCK_FCLOSE( cndes->sin );
  107. MEM_FREE(cndes);
  108. return 0;
  109. }
  110. if( ! SOCK_FGETS(msgbuf, sizeof(msgbuf), cndes->sin ) )
  111. {
  112. SOCK_FCLOSE( cndes->sin );
  113. SOCK_FCLOSE( cndes->sout );
  114. MEM_FREE(cndes);
  115. return 0;
  116. }
  117. /* a patch from Julia Anne Case <julie@magenet.com> */
  118. SOCK_FPUTS("MODE READER\r\n", cndes->sout);
  119. if( SOCK_FFLUSH(cndes->sout) == EOF )
  120. return 0;
  121. if( ! SOCK_FGETS(msgbuf, sizeof(msgbuf), cndes->sin ) )
  122. {
  123. SOCK_FCLOSE( cndes->sin );
  124. SOCK_FCLOSE( cndes->sout );
  125. MEM_FREE(cndes);
  126. return 0;
  127. }
  128. switch( atoi( msgbuf ) )
  129. {
  130. case NNTP_POST_CONN_OK:
  131. cndes->postok = 1;
  132. break;
  133. case NNTP_READ_CONN_OK:
  134. cndes->postok = 0;
  135. break;
  136. default:
  137. SOCK_FCLOSE( cndes->sin );
  138. SOCK_FCLOSE( cndes->sout );
  139. MEM_FREE(cndes);
  140. return 0;
  141. }
  142. cndes->code = 0;
  143. /* group info */
  144. cndes->start= 0L;
  145. cndes->end = 0L;
  146. cndes->count= 0;
  147. cndes->mode = 0;
  148. return (void*)cndes;
  149. }
  150. void nntp_close(void* hcndes)
  151. {
  152. nntp_cndes_t* pcndes = (nntp_cndes_t*)hcndes;
  153. char msgbuf[128];
  154. SOCK_FPUTS( "QUIT\r\n", pcndes->sout );
  155. SOCK_FFLUSH( pcndes->sout );
  156. SOCK_FGETS(msgbuf, sizeof(msgbuf), pcndes->sin );
  157. SOCK_FCLOSE( pcndes->sin );
  158. SOCK_FCLOSE( pcndes->sout );
  159. MEM_FREE( hcndes );
  160. #ifdef WINSOCK
  161. WSACleanup();
  162. #endif
  163. }
  164. int nntp_errcode( void* hcndes )
  165. {
  166. if( ! hcndes )
  167. return -1;
  168. return ((nntp_cndes_t*)hcndes)->code;
  169. }
  170. char* nntp_errmsg( void* hcndes )
  171. {
  172. int i, errcode;
  173. errcode = nntp_errcode( hcndes );
  174. switch( errcode )
  175. {
  176. case 0:
  177. return 0;
  178. case -1:
  179. return strerror( errno );
  180. default:
  181. break;
  182. }
  183. for(i=0;i<sizeof(nntp_msg)/sizeof(nntp_msg[0]);i++)
  184. {
  185. if( nntp_msg[i].code == errcode )
  186. return nntp_msg[i].msg;
  187. }
  188. return 0;
  189. }
  190. int nntp_postok( void* hcndes )
  191. {
  192. return ((nntp_cndes_t*)hcndes)->postok;
  193. }
  194. int nntp_group( void* hcndes, char* grpnam )
  195. {
  196. nntp_cndes_t* pcndes = hcndes;
  197. char response[64];
  198. int code;
  199. pcndes->code = -1; /* system error */
  200. SOCK_FPRINTF( pcndes->sout, "GROUP %s\r\n", grpnam);
  201. if( SOCK_FFLUSH( pcndes->sout ) == EOF )
  202. return -1;
  203. if( ! SOCK_FGETS( response, sizeof( response ), pcndes->sin ) )
  204. return -1;
  205. code = atoi(response);
  206. if( code != NNTP_GROUP_OK )
  207. {
  208. pcndes->code = code;
  209. return -1;
  210. }
  211. sscanf( response, "%d%d%ld%ld",
  212. &code, &(pcndes->count),
  213. &(pcndes->start), &(pcndes->end));
  214. pcndes->code = 0;
  215. return 0;
  216. }
  217. char* nntp_body( void* hcndes, long msgnum, char* msgid)
  218. {
  219. nntp_cndes_t* pcndes = hcndes;
  220. char tmsgbuf[128];
  221. int code;
  222. char* body;
  223. int totsize, freesize, offset;
  224. pcndes->code = -1;
  225. if( msgnum > 0 )
  226. SOCK_FPRINTF(pcndes->sout, "BODY %ld\r\n", msgnum );
  227. else if( msgid )
  228. SOCK_FPRINTF(pcndes->sout, "BODY %s\r\n", msgid );
  229. else
  230. {
  231. SOCK_FPUTS("BODY\r\n", pcndes->sout);
  232. }
  233. if( SOCK_FFLUSH( pcndes->sout ) == EOF )
  234. return 0;
  235. if( ! SOCK_FGETS(tmsgbuf, sizeof(tmsgbuf), pcndes->sin ) )
  236. return 0;
  237. code = atoi(tmsgbuf);
  238. if( code != NNTP_BODY_OK )
  239. {
  240. pcndes->code = code;
  241. return 0;
  242. }
  243. body = MEM_ALLOC(BODY_CHUNK_SIZE);
  244. if( !body )
  245. abort();
  246. totsize = freesize = BODY_CHUNK_SIZE;
  247. offset = 0;
  248. for(;;)
  249. {
  250. if( freesize <= BODY_CHUNK_SIZE/2 )
  251. {
  252. totsize += BODY_CHUNK_SIZE;
  253. freesize += BODY_CHUNK_SIZE;
  254. body = MEM_REALLOC(body, totsize);
  255. if( ! body )
  256. abort();
  257. }
  258. if( ! SOCK_FGETS( body + offset, freesize, pcndes->sin ) )
  259. return 0;
  260. if( STREQ( body+offset, ".\r\n") )
  261. {
  262. *(body+offset) = 0;
  263. break;
  264. }
  265. /* strip off CR i.e '\r' */
  266. offset += STRLEN(body+offset) - 1;
  267. freesize = totsize - offset;
  268. body[offset-1] = '\n';
  269. }
  270. return body;
  271. }
  272. int nntp_next( void* hcndes )
  273. {
  274. nntp_cndes_t* pcndes = hcndes;
  275. char tmsgbuf[128];
  276. int code;
  277. pcndes->code = -1;
  278. SOCK_FPUTS("NEXT\r\n", pcndes->sout);
  279. if( SOCK_FFLUSH( pcndes->sout ) == EOF )
  280. return -1;
  281. if( ! SOCK_FGETS( tmsgbuf, sizeof(tmsgbuf), pcndes->sin) )
  282. return -1;
  283. pcndes->code = atoi(tmsgbuf);
  284. switch( pcndes->code )
  285. {
  286. case NNTP_END_OF_GROUP:
  287. return 100;
  288. case NNTP_NEXT_OK:
  289. return 0;
  290. default:
  291. break;
  292. }
  293. return -1;
  294. }
  295. int nntp_last( void* hcndes )
  296. {
  297. nntp_cndes_t* pcndes = hcndes;
  298. char tmsgbuf[128];
  299. int code, sock;
  300. char* body;
  301. int size;
  302. pcndes->code = -1;
  303. SOCK_FPUTS("LAST\r\n", pcndes->sout);
  304. if( SOCK_FFLUSH( pcndes->sout ) == EOF )
  305. return -1;
  306. if( ! SOCK_FGETS( tmsgbuf, sizeof(tmsgbuf), pcndes->sin) )
  307. return -1;
  308. pcndes->code = atoi(tmsgbuf);
  309. switch( pcndes->code )
  310. {
  311. case NNTP_TOP_OF_GROUP:
  312. return 100;
  313. case NNTP_LAST_OK:
  314. return 0;
  315. default:
  316. break;
  317. }
  318. return -1;
  319. }
  320. static int nntp_xhdr( void* hcndes, nntp_xhdrinfo_t* xhdr_data)
  321. {
  322. nntp_cndes_t* pcndes = hcndes;
  323. char tbuf[128];
  324. int totsize, freesize;
  325. int flag;
  326. char* ptr;
  327. pcndes->code = -1;
  328. xhdr_data->count = 0;
  329. SOCK_FPRINTF( pcndes->sout, "XHDR %s %ld-%ld\r\n",
  330. xhdr_data->header, xhdr_data->start, xhdr_data->end );
  331. if( SOCK_FFLUSH( pcndes->sout ) == EOF )
  332. return -1;
  333. if( ! SOCK_FGETS( tbuf, sizeof(tbuf), pcndes->sin ) )
  334. return -1;
  335. pcndes->code = atoi(tbuf);
  336. if( pcndes->code != NNTP_XHDR_OK )
  337. return -1;
  338. flag = upper_strneq(xhdr_data->header, "lines", 6);
  339. if( flag )
  340. {
  341. xhdr_data->buf = 0;
  342. }
  343. else
  344. {
  345. totsize = freesize = XHDR_CHUNK_SIZE;
  346. xhdr_data->buf = MEM_ALLOC(totsize);
  347. if( ! xhdr_data->buf )
  348. return -1;
  349. ptr = xhdr_data->buf;
  350. }
  351. for(xhdr_data->count=0;;xhdr_data->count++)
  352. {
  353. int num;
  354. if( flag )
  355. {
  356. if( ! SOCK_FGETS(tbuf, sizeof(tbuf), pcndes->sin) )
  357. return -1;
  358. if( STRNEQ(tbuf, ".\r\n", 3) )
  359. break;
  360. sscanf(tbuf, "%ld%ld",
  361. &(xhdr_data->idxs[xhdr_data->count].article_num),
  362. &(xhdr_data->idxs[xhdr_data->count].data) );
  363. }
  364. else
  365. {
  366. if( freesize < XHDR_CHUNK_SIZE/2 )
  367. {
  368. int offset;
  369. totsize += XHDR_CHUNK_SIZE;
  370. freesize += XHDR_CHUNK_SIZE;
  371. offset = (int)(ptr - xhdr_data->buf);
  372. xhdr_data->buf = MEM_REALLOC( xhdr_data->buf, totsize );
  373. if( ! xhdr_data->buf )
  374. return -1;
  375. ptr = xhdr_data->buf + offset;
  376. }
  377. if( ! SOCK_FGETS(ptr, freesize, pcndes->sin ) )
  378. return -1;
  379. if( STRNEQ(ptr, ".\r\n", 3) )
  380. break;
  381. sscanf( ptr, "%ld%n",
  382. &(xhdr_data->idxs[xhdr_data->count].article_num),
  383. &num);
  384. if( STREQ( ptr + num + 1, "(none)\r\n") )
  385. {
  386. xhdr_data->idxs[xhdr_data->count].data = 0;
  387. ptr += (num + 1);
  388. }
  389. else
  390. {
  391. xhdr_data->idxs[xhdr_data->count].data =
  392. ptr - xhdr_data->buf + num + 1;
  393. ptr += (STRLEN(ptr) - 1);
  394. }
  395. ptr[-1] = 0;
  396. freesize = totsize - (int)(ptr - xhdr_data->buf);
  397. }
  398. }
  399. return 0;
  400. }
  401. typedef struct {
  402. void* hcndes;
  403. char header[20];
  404. nntp_xhdrinfo_t* hdrinfo;
  405. long position;
  406. long last;
  407. } nntp_header_t;
  408. void* nntp_openheader(void* hcndes, char* header, long* tmin, long* tmax)
  409. {
  410. nntp_cndes_t* pcndes = hcndes;
  411. nntp_header_t* hd;
  412. long start;
  413. pcndes->code = -1;
  414. hd = (nntp_header_t*)MEM_ALLOC(sizeof(nntp_header_t));
  415. if( !hd )
  416. return 0;
  417. hd->hcndes = hcndes;
  418. STRCPY(hd->header, header);
  419. hd->last = pcndes->end;
  420. hd->hdrinfo = (nntp_xhdrinfo_t*)MEM_ALLOC(sizeof(nntp_xhdrinfo_t));
  421. if( !hd->hdrinfo )
  422. {
  423. MEM_FREE( hd );
  424. return 0;
  425. }
  426. start = pcndes->start;
  427. if( *tmax < *tmin )
  428. {
  429. #ifndef MAX_SIGNED_LONG
  430. # define MAX_SIGNED_LONG ( (-1UL) >> 1 )
  431. #endif
  432. if( start < *tmax || start > *tmin )
  433. *tmin = start;
  434. *tmax = MAX_SIGNED_LONG;
  435. }
  436. if( *tmin < start )
  437. *tmin = start;
  438. if( *tmin == MAX_SIGNED_LONG )
  439. *tmin = *tmax = 0L;
  440. hd->hdrinfo->header = hd->header;
  441. hd->hdrinfo->start = 0L;
  442. hd->hdrinfo->end = *tmin - 1L;
  443. hd->hdrinfo->count = 0;
  444. hd->hdrinfo->idxs = (nntp_xhdridx_t*)MEM_ALLOC(
  445. sizeof(nntp_xhdridx_t)*NNTP_HEADER_CHUNK);
  446. if( ! hd->hdrinfo->idxs )
  447. {
  448. MEM_FREE( hd->hdrinfo );
  449. MEM_FREE( hd );
  450. return 0;
  451. }
  452. hd->hdrinfo->buf = 0;
  453. hd->position = 0;
  454. return hd;
  455. }
  456. void nntp_closeheader(void* hh)
  457. {
  458. nntp_header_t* ph = hh;
  459. if( !hh )
  460. return;
  461. if( ph->hdrinfo )
  462. {
  463. MEM_FREE( ph->hdrinfo->idxs );
  464. MEM_FREE( ph->hdrinfo->buf );
  465. MEM_FREE( ph->hdrinfo );
  466. }
  467. MEM_FREE( hh );
  468. }
  469. int nntp_fetchheader( void* hh, long* artnum, long* data, void* hrh)
  470. {
  471. nntp_header_t* ph = hh;
  472. nntp_header_t* prh= hrh; /* reference header */
  473. nntp_cndes_t* pcndes;
  474. long position;
  475. long ldata;
  476. if(! hh )
  477. return -1;
  478. pcndes = ph->hcndes;
  479. position = ph->position;
  480. pcndes->code = -1;
  481. if( ph->hdrinfo->start >= ph->last )
  482. return 100;
  483. if( prh )
  484. {
  485. if( ph->hdrinfo->end != prh->hdrinfo->end )
  486. {
  487. MEM_FREE(ph->hdrinfo->buf);
  488. ph->hdrinfo->buf = 0;
  489. ph->hdrinfo->start = prh->hdrinfo->start;
  490. ph->hdrinfo->end = prh->hdrinfo->end;
  491. if( nntp_xhdr( pcndes, ph->hdrinfo ) )
  492. return -1;
  493. }
  494. position = ph->position = prh->position-1;
  495. }
  496. else if( ph->hdrinfo->count == position )
  497. {
  498. MEM_FREE(ph->hdrinfo->buf);
  499. ph->hdrinfo->buf = 0;
  500. for(;;)
  501. {
  502. ph->hdrinfo->start = ph->hdrinfo->end + 1;
  503. ph->hdrinfo->end = ph->hdrinfo->end + NNTP_HEADER_CHUNK;
  504. ph->hdrinfo->count = 0;
  505. position = ph->position = 0;
  506. if( ph->hdrinfo->start > ph->last )
  507. return 100;
  508. if( nntp_xhdr( pcndes, ph->hdrinfo ) )
  509. return -1;
  510. if( ph->hdrinfo->count )
  511. break;
  512. }
  513. }
  514. if( artnum )
  515. *artnum = (ph->hdrinfo->idxs)[position].article_num;
  516. ldata = (ph->hdrinfo->idxs)[position].data;
  517. if( ldata )
  518. ldata = (long)(ph->hdrinfo->buf) + ldata;
  519. if( data )
  520. *data = ldata;
  521. ph->position ++;
  522. return 0;
  523. }
  524. int nntp_start_post(void* hcndes)
  525. {
  526. nntp_cndes_t* pcndes = hcndes;
  527. char msgbuf[128];
  528. int i;
  529. pcndes->code = -1;
  530. if( ! nntp_postok(hcndes) )
  531. {
  532. pcndes->code = NNTP_CANNOT_POST;
  533. return -1;
  534. }
  535. SOCK_FPUTS( "POST\r\n", pcndes->sout );
  536. if( SOCK_FFLUSH( pcndes->sout ) == EOF )
  537. return -1;
  538. if( ! SOCK_FGETS(msgbuf, sizeof(msgbuf), pcndes->sin) )
  539. return -1;
  540. pcndes->code = atoi(msgbuf);
  541. if(pcndes->code != NNTP_POSTING )
  542. return -1;
  543. return 0;
  544. }
  545. int nntp_send_head(void* hcndes, char* head_name, char* head)
  546. {
  547. nntp_cndes_t* pcndes = hcndes;
  548. int i;
  549. for(i=0;head[i];i++)
  550. /* to make sure there is no new line char in a head string
  551. * here, head must be pointed to a writeable area and don't
  552. * care whether it will be overwritten after posting */
  553. {
  554. if( head[i] == '\n' )
  555. {
  556. head[i] = 0;
  557. break;
  558. }
  559. }
  560. SOCK_FPRINTF( pcndes->sout, "%s: %s\n",
  561. head_name, head);
  562. return 0;
  563. }
  564. int nntp_end_head(void* hcndes)
  565. {
  566. nntp_cndes_t* pcndes = hcndes;
  567. SOCK_FPUTS("\n", pcndes->sout);
  568. return 0;
  569. }
  570. int nntp_send_body(void* hcndes, char* body)
  571. {
  572. nntp_cndes_t* pcndes = hcndes;
  573. char* ptr;
  574. for(ptr=body;*ptr;ptr++)
  575. /* we require the article body buffer is located in a
  576. * writeable area and can be overwritten during the
  577. * post action.
  578. */
  579. {
  580. if( *ptr == '\n' )
  581. {
  582. if( STRNEQ( ptr, "\n.\n", 3)
  583. || STRNEQ( ptr, "\n.\r\n", 4 ) )
  584. {
  585. *ptr = 0;
  586. break;
  587. }
  588. }
  589. }
  590. SOCK_FPUTS(body, pcndes->sout);
  591. return 0;
  592. }
  593. int nntp_end_post(void* hcndes)
  594. {
  595. nntp_cndes_t* pcndes = hcndes;
  596. char msgbuf[128];
  597. pcndes->code = -1;
  598. SOCK_FPUTS("\r\n.\r\n", pcndes->sout);
  599. if( SOCK_FFLUSH(pcndes->sout) == EOF )
  600. return -1;
  601. if( ! SOCK_FGETS(msgbuf, sizeof(msgbuf), pcndes->sin) )
  602. return -1;
  603. pcndes->code = atoi(msgbuf);
  604. if( pcndes->code != NNTP_POST_OK )
  605. return -1;
  606. return 0;
  607. }
  608. int nntp_cancel(
  609. void* hcndes,
  610. char* group,
  611. char* sender,
  612. char* from,
  613. char* msgid )
  614. {
  615. char msgbuf[128];
  616. if( ! from )
  617. from = "(none)";
  618. sprintf( msgbuf, "cancel %s", msgid);
  619. if( nntp_start_post(hcndes)
  620. || nntp_send_head(hcndes, "Newsgroups", group)
  621. || ( sender && nntp_send_head(hcndes, "Sender", sender) )
  622. || nntp_send_head(hcndes, "From", from)
  623. || nntp_send_head(hcndes, "Control", msgbuf)
  624. || nntp_end_head(hcndes)
  625. || nntp_end_post(hcndes) )
  626. return -1;
  627. return 0;
  628. }
  629. void nntp_setaccmode(void* hcndes, int mode)
  630. {
  631. nntp_cndes_t* pcndes = hcndes;
  632. pcndes->mode = mode;
  633. }
  634. int nntp_getaccmode(void* hcndes )
  635. {
  636. nntp_cndes_t* pcndes = hcndes;
  637. return pcndes->mode;
  638. }