popcli.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:10k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /*
  2.  * POP2 Client routines.  Originally authored by Mike Stockett
  3.  *   (WA7DYX).
  4.  * Modified 12 May 1991 by Mark Edwards (WA6SMN) to use new timer
  5.  * facilities in NOS0423.  Fixed type mismatches spotted by C++.
  6.  * Modified 27 May 1990 by Allen Gwinn (N5CKP) for compatibility
  7.  *   with later releases (NOS0522).
  8.  * Added into NOS by PA0GRI (and linted into "standard" C)
  9.  *
  10.  * Some code culled from previous releases of SMTP.
  11.  *
  12.  * Client routines for Simple Mail Transfer Protocol ala RFC821
  13.  * A.D. Barksdale Garbee II, aka Bdale, N3EUA
  14.  * Copyright 1986 Bdale Garbee, All Rights Reserved.
  15.  * Permission granted for non-commercial copying and use, provided
  16.  *   this notice is retained.
  17.  *  Modified 14 June 1987 by P. Karn for symbolic target addresses,
  18.  *   also rebuilt locking mechanism
  19.  * Copyright 1987 1988 David Trulli, All Rights Reserved.
  20.  * Permission granted for non-commercial copying and use, provided
  21.  * this notice is retained.
  22.  */
  23. #include <stdio.h>
  24. #include <fcntl.h>
  25. #include <time.h>
  26. #include <setjmp.h>
  27. #ifdef UNIX
  28. #include <sys/types.h>
  29. #endif
  30. #ifdef __TURBOC__
  31. #include <dir.h>
  32. #include <io.h>
  33. #endif
  34. #include "global.h"
  35. #include <stdarg.h>
  36. #include "mbuf.h"
  37. #include "cmdparse.h"
  38. #include "proc.h"
  39. #include "socket.h"
  40. #include "timer.h"
  41. #include "netuser.h"
  42. #include "dirutil.h"
  43. #include "files.h"
  44. extern char Badhost[];
  45. #define BUF_LEN 257
  46. /* POP client control block */
  47. struct pop_ccb {
  48. FILE *network; /* Network stream for this connection */
  49. char state; /* client state */
  50. #define    CALL 0
  51. #define    NMBR 3
  52. #define    SIZE 5
  53. #define    XFER 8
  54. #define    EXIT 10
  55. char buf[BUF_LEN], /* tcp input buffer */
  56. count; /* input buffer length */
  57. int folder_len; /* number of msgs in current folder */
  58. long msg_len; /* length of current msg */
  59. int msg_num; /* current message number */
  60. } *ccb;
  61. static int Popquiet = 0;
  62. static struct timer  popcli_t;
  63. static int32 mailhost;
  64. static char mailbox_name[10],
  65. mailbox_pathname[BUF_LEN],
  66. username[20],
  67. password[20],
  68. Workfile_name[] ="mbox.pop";
  69. static int domailbox(int argc,char *argv[],void *p);
  70. static int domailhost(int argc,char *argv[],void *p);
  71. static int douserdata(int argc,char *argv[],void *p);
  72. static int doquiet(int argc,char *argv[],void *p);
  73. static int dotimer(int argc,char *argv[],void *p);
  74. static struct pop_ccb  *new_ccb(void);
  75. static void delete_ccb(void);
  76. static void pop_send(int unused,void *cb1,void *p);
  77. static int popkick(int argc,char *argv[],void *p);
  78. /* I don't know why this isn't static, it isn't called anywhere else {was} */
  79. int poptick(void);
  80. static struct cmds Popcmds[] = {
  81. "mailbox", domailbox, 0, 0, NULL,
  82. "mailhost", domailhost, 0, 0, NULL,
  83. "kick", popkick, 0, 0, NULL,
  84. "quiet", doquiet, 0, 0, NULL,
  85. "timer", dotimer, 0, 0, NULL,
  86. "userdata", douserdata, 0, 0, NULL,
  87. NULL,
  88. };
  89. /* Command string specifications */
  90. static char ackd_cmd[] = "ACKDn",
  91. #ifdef POP_FOLDERS
  92. fold_cmd[] = "FOLD %sn",
  93. #endif
  94. login_cmd[] = "HELO %s %sn",
  95. /* nack_cmd[]      = "NACKn",     /* Not implemented */
  96. quit_cmd[]      = "QUITn",
  97. read_cur_cmd[]  = "READn",
  98. retr_cmd[]      = "RETRn";
  99. /* Response string keys */
  100. static char *greeting_rsp  = "+ POP2 ";
  101. FILE *fd;
  102. int
  103. dopop(argc,argv,p)
  104. int  argc;
  105. char  *argv[];
  106. void  *p;
  107. {
  108. return subcmd(Popcmds,argc,argv,p);
  109. }
  110. static int
  111. domailbox(argc,argv,p) 
  112. int argc;
  113. char *argv[];
  114. void *p;
  115. {
  116. if(argc < 2) {
  117. if(mailbox_name[0] == '')
  118. printf("maibox name not set yetn");
  119. else
  120. printf("%sn",mailbox_name);
  121. } else {
  122. strncpy(mailbox_name,argv[1],10);
  123. }
  124. return 0;
  125. }
  126. static int
  127. domailhost(argc,argv,p)
  128. int argc;
  129. char *argv[];
  130. void *p;
  131. {
  132. int32 n;
  133. if(argc < 2) {
  134. printf("%sn",inet_ntoa(mailhost));
  135. } else
  136. if((n = resolve(argv[1])) == 0) {
  137. printf(Badhost,argv[1]);
  138. return 1;
  139. } else
  140. mailhost = n;
  141. return 0;
  142. }
  143. static int
  144. doquiet(argc,argv,p)
  145. int argc;
  146. char *argv[];
  147. void *p;
  148. {
  149. return setbool(&Popquiet,"POP quiet",argc,argv);
  150. }
  151. static int
  152. douserdata(argc,argv,p)
  153. int argc;
  154. char *argv[];
  155. void *p;
  156. {
  157. if (argc < 2)
  158. printf("%sn",username);
  159. else if (argc != 3) {
  160. printf("Usage: pop userdata <username> <password>n");
  161. return 1;
  162. } else {
  163. sscanf(argv[1],"%18s",username);
  164. sscanf(argv[2],"%18s",password);
  165. }
  166. return 0;
  167. }
  168. /* Set scan interval */
  169. static int
  170. dotimer(argc,argv,p)
  171. int argc;
  172. char *argv[];
  173. void *p;
  174. {
  175. if(argc < 2) {
  176. printf("%lu/%lun",
  177. read_timer(&popcli_t) /1000L,
  178. dur_timer(&popcli_t)/ 1000L);
  179. return 0;
  180. }
  181. popcli_t.func  = (void (*)())poptick;   /* what to call on timeout */
  182. popcli_t.arg   = NULL; /* dummy value */
  183. set_timer(&popcli_t, atol(argv[1])*1000L);  /* set timer duration */
  184. start_timer(&popcli_t); /* and fire it up */
  185. return 0;
  186. }
  187. static int
  188. popkick(argc,argv,p)
  189. int argc;
  190. char *argv[];
  191. void *p;
  192. {
  193. poptick();
  194. return 0;
  195. }
  196. int
  197. poptick()
  198. {
  199. if (ccb == NULL) {
  200. /* Don't start if any of the required parameters have not been specified */
  201. if (mailhost == 0) {
  202. printf("mailhost not defined yet.(pop mailhost <host>)n");
  203. return 0;
  204. }
  205. if (mailbox_name[0] == '') {
  206. printf("mailbox name not defined yet.(pop mailbox <name>)n");
  207. return 0;
  208. }
  209. if (username[0] == '') {
  210. printf("username not defined yet. (pop user <name> <pass>)n");
  211. return 0;
  212. }
  213. if (password[0] == '') {
  214. printf(" Unknown passwordn");
  215. return 0;
  216. }
  217. if ((ccb = new_ccb()) == NULL) {
  218. fprintf(stderr,"*** Unable to allocate CCB");
  219. return 0;
  220. }
  221. newproc("Auto-POP Client",1024,pop_send,0,ccb,NULL,0);
  222. }
  223. /* Restart timer */
  224. start_timer(&popcli_t);
  225. return 0;
  226. }
  227. /* this is the master state machine that handles a single SMTP transaction */
  228. /* it is called with a queue of jobs for a particular host. */
  229. static void
  230. pop_send(unused,cb1,p) 
  231. int unused;
  232. void *cb1;
  233. void *p;
  234. {
  235. char *cp;
  236. struct sockaddr_in fsocket;
  237. struct pop_ccb *ccb;
  238. void pop_csm(struct pop_ccb *);
  239. void quit_session(struct pop_ccb *);
  240. int s;
  241. ccb = (struct pop_ccb *)cb1;
  242. fsocket.sin_family = AF_INET;
  243. fsocket.sin_addr.s_addr = mailhost;
  244. fsocket.sin_port = IPPORT_POP;
  245. s = socket(AF_INET,SOCK_STREAM,0);
  246. ccb->state = CALL;
  247. if (connect(s,(struct sockaddr *)&fsocket,SOCKSIZE) == 0) {
  248. logmsg(s,"Connected to mailhost %s", inet_ntoa(mailhost));
  249. ccb->network = fdopen(s,"r+t");
  250. } else {
  251. cp = sockerr(s);
  252. logmsg(s,"Connect to mailhost %s failed: %s", inet_ntoa(mailhost),
  253.     (cp != NULL)? cp: "");
  254. }
  255. while(1) {
  256. if (fgets(ccb->buf,BUF_LEN,ccb->network) == NULL)
  257. goto quit;
  258. rip(ccb->buf);
  259. pop_csm(ccb);
  260. if (ccb->state == EXIT)
  261. goto quit;
  262. }
  263. quit:
  264. logmsg(s,"Connection closed to mailhost %s", inet_ntoa(mailhost));
  265. fclose(ccb->network);
  266. if (fd != NULL)
  267. fclose(fd);
  268. delete_ccb();
  269. }
  270. /* free the message struct and data */
  271. static void
  272. delete_ccb()
  273. {
  274. if (ccb == NULL)
  275. return;
  276. free(ccb);
  277. ccb = NULL;
  278. }
  279. /* create a new  pop control block */
  280. static struct
  281. pop_ccb *new_ccb()
  282. {
  283. register struct pop_ccb *ccb;
  284. if ((ccb = (struct pop_ccb *) callocw(1,sizeof(struct pop_ccb))) == NULL)
  285. return(NULL);
  286. return(ccb);
  287. }
  288. /* ---------------------- pop client code starts here --------------------- */
  289. void
  290. pop_csm(ccb)
  291. struct pop_ccb *ccb;
  292. {
  293. FILE *mf;
  294. int mlock (char *,char *);
  295. int rmlock (char * ,char *);
  296. void quit_session(struct pop_ccb *);
  297. /* int mlock(char *dir,char *id);   */
  298. /* int rmlock(char *dir,char *id);   */
  299. switch(ccb->state) {
  300. case CALL:
  301. if (strncmp(ccb->buf,greeting_rsp,strlen(greeting_rsp)) == 0) {
  302.  fprintf(ccb->network,login_cmd,username,password);
  303. ccb->state = NMBR;
  304. } else
  305. (void) quit_session(ccb);
  306. break;
  307. case NMBR:
  308. switch (ccb->buf[0]) {
  309. case '#':
  310. if ((fd = fopen(Workfile_name,"a+")) == NULL) {
  311. perror("Unable to open work file");
  312. quit_session(ccb);
  313. return;
  314. }
  315. fseek(fd,0,SEEK_SET);
  316. ccb->folder_len = atoi(&(ccb->buf[1]));
  317. fprintf(ccb->network,read_cur_cmd);
  318. ccb->state = SIZE;
  319. break;
  320. case '+':
  321. /* If there is no mail (the only time we get a "+"
  322.  * response back at this stage of the game),
  323.  * then just close out the connection, because
  324.  * there is nothing more to do!! */
  325. default:
  326. quit_session(ccb);
  327. break;
  328. }
  329. break;
  330. case SIZE:
  331. if (ccb->buf[0] == '=') {
  332. ccb->msg_len = atol(&(ccb->buf[1]));
  333. if (ccb->msg_len > 0) {
  334. fprintf(ccb->network,retr_cmd);
  335. ccb->state = XFER;
  336. } else {
  337. logmsg(fileno(ccb->network),"POP client retrieved %d messages",
  338.     ccb->folder_len);
  339. /* All done, so do local cleanup */
  340. if (mlock(Mailspool,mailbox_name)) {
  341. printf("n*** Local mailbox locked, new mail in file %sn",
  342.  Workfile_name);
  343. quit_session(ccb);
  344. return;
  345. }
  346. sprintf(mailbox_pathname,"%s/%s.txt",Mailspool,
  347. mailbox_name);
  348. if ((mf = fopen(mailbox_pathname,"a+")) == NULL) {
  349. printf("n*** Unable to open local mailbox, new mail in file %sn",
  350.        Workfile_name);
  351. quit_session(ccb);
  352. return;
  353. }
  354. fseek(fd,0,SEEK_SET);
  355. while (!feof(fd)) {
  356. if(fgets(ccb->buf,BUF_LEN,fd) != NULL) {
  357. fputs(ccb->buf,mf);
  358. }
  359. }
  360. fclose(mf);
  361. fclose(fd);
  362. fd = NULL;
  363. printf("New mail arrived for %s from mailhost <%s>%cn",
  364. mailbox_name, inet_ntoa(mailhost),
  365. Popquiet ? ' ' : '07');
  366. rmlock(Mailspool,mailbox_name);
  367. unlink(Workfile_name);
  368. quit_session(ccb);
  369. }
  370. } else
  371. quit_session(ccb);
  372. break;
  373. case XFER:
  374. fprintf(fd,"%sn",ccb->buf);
  375. ccb->msg_len -= (long)(strlen(ccb->buf)+2); /* Add CRLF */
  376. if (ccb->msg_len > 0)
  377. return;
  378. fprintf(ccb->network,ackd_cmd);
  379. ccb->msg_num++;
  380. ccb->state = SIZE;
  381. break;
  382. case EXIT:
  383. if (fd != NULL)
  384. fclose(fd);
  385. break;
  386. default:
  387. break;
  388. }
  389. }
  390. void
  391. quit_session(ccb)
  392. struct pop_ccb *ccb;
  393. {
  394. fprintf(ccb->network,quit_cmd);
  395. ccb->state  = EXIT;
  396. }