* clear out some warnings by gcc 9.3.1.
[alpine.git] / alpine / rpdump.c
blobc5b59d111648ba10d0a1b14a4e4c85faccc4c61f
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: rpdump.c 1074 2008-06-04 00:08:43Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2013-2020 Eduardo Chappa
8 * Copyright 2006-2008 University of Washington
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
19 #include "headers.h"
20 #include "radio.h" /* OE_PASSWD */
21 #include "../pith/util.h" /* IS_REMOTE() */
22 #include "../pith/remote.h" /* REMOTE_ABOOK_SUBTYPE... */
25 typedef enum {Pinerc, Abook, Sig, Smime, NotSet} RemoteType;
28 int parse_args(int, char **, int *, char **, char **);
29 RemoteType check_for_header_msg(MAILSTREAM *);
30 char *ptype(RemoteType);
31 char *spechdr(RemoteType);
32 char *err_desc(int);
33 int opt_enter(char *, int, char *, int *);
34 char *last_cmpnt(char *);
35 int wantto(char *, int, int);
38 char *ustr = "usage: %s [-f] -l Local_file -r Remote_folder\n";
39 int noshow_error = 0;
41 /* look for my_timer_period in pico directory for an explanation */
42 int my_timer_period = ((IDLE_TIMEOUT + 1)*1000);
45 #ifdef _WINDOWS
47 #undef main
49 app_main (argc, argv)
50 int argc;
51 char argv[];
55 #endif /* _WINDOWS */
59 * rpdump [-f] -l Local_file -r Remote_folder
61 * -f (skip check for special header)
63 * Note: We're not worrying about memory leaks.
65 int
66 main(argc, argv)
67 int argc;
68 char *argv[];
70 MAILSTREAM *stream = NULL;
71 FILE *fp;
72 int usage = 0;
73 char buf[10000];
74 char *local = NULL, *remote = NULL;
75 int force = 0;
76 BODY *body = NULL;
77 char *data, *p;
78 RemoteType rtype;
79 unsigned long i;
80 struct stat sbuf;
82 #include "../c-client/linkage.c"
84 if(parse_args(argc, argv, &force, &local, &remote)){
85 fprintf(stderr, ustr, argv[0]);
86 exit(-1);
89 if(!local || !*local){
90 fprintf(stderr, "No local file specified\n");
91 usage++;
94 if(!remote || !*remote){
95 fprintf(stderr, "No remote folder specified\n");
96 usage++;
99 if(usage){
100 fprintf(stderr, ustr, argv[0]);
101 exit(-1);
104 if(!IS_REMOTE(remote)){
105 fprintf(stderr,
106 "Remote folder name \"%s\" %s\n", remote,
107 (*remote != '{') ? "must begin with \"{\"" : "not valid");
108 exit(-1);
111 if(IS_REMOTE(local)){
112 fprintf(stderr, "Argument to -l (%s) must be a local filename", local);
113 exit(-1);
116 #ifdef _WINDOWS
117 if(stat(local, &sbuf))
118 #else
119 if(lstat(local, &sbuf))
120 #endif
122 if(errno == ENOENT){ /* File did not exist */
123 int fd;
125 /* create it */
126 if(((fd = open(local, O_CREAT|O_EXCL|O_WRONLY,0600)) < 0)
127 || (close(fd) != 0)){
128 fprintf(stderr, "%s: %s\n", local, err_desc(errno));
129 exit(-1);
132 /* now it exists! */
134 else{ /* unknown error */
135 fprintf(stderr, "%s: %s\n", local, err_desc(errno));
136 exit(-1);
139 else{ /* file exists */
141 /* is it a regular file? */
142 #ifdef S_ISREG
143 if(!S_ISREG(sbuf.st_mode))
144 #else
145 if(!(S_IFREG & sbuf.st_mode))
146 #endif
148 fprintf(stderr, "Only allowed to write to regular local files. Try another filename.\n");
149 exit(-1);
152 if(access(local, WRITE_ACCESS) == 0){
154 snprintf(buf, sizeof(buf), "Local file \"%s\" exists, overwrite it",
155 (p = last_cmpnt(local)) ? p : local);
156 if(wantto(buf, 'n', 'n') != 'y'){
157 fprintf(stderr, "Dump cancelled\n");
158 exit(-1);
161 else{
162 fprintf(stderr, "Local file \"%s\" is not writable\n", local);
163 exit(-1);
168 * Try opening the local file.
170 if((fp = fopen(local, "w")) == NULL){
171 fprintf(stderr, "Can't open \"%s\": %s\n", local, err_desc(errno));
172 mail_close(stream);
173 exit(-1);
177 * Try opening the remote folder.
179 stream = mail_open(NULL, remote, OP_READONLY);
180 if(!stream || stream->halfopen){
181 fprintf(stderr, "Remote folder \"%s\" is not readable\n", remote);
182 if(stream)
183 mail_close(stream);
185 exit(-1);
188 if(stream->nmsgs >= 2){
190 * There is a first message already. Check to see if it is one of
191 * our special header messages.
193 rtype = check_for_header_msg(stream);
194 if(!force && rtype == NotSet){
195 fprintf(stderr, "Folder \"%s\"\ndoes not appear to be an Alpine remote data folder.\nUse -f to force.\n", remote);
196 mail_close(stream);
197 exit(-1);
200 else if(stream->nmsgs == 1){
201 fprintf(stderr, "No data in remote folder to copy (only 1 message)\n");
202 mail_close(stream);
203 exit(-1);
205 else{
206 fprintf(stderr, "No data in remote folder to copy\n");
207 mail_close(stream);
208 exit(-1);
211 if(!mail_fetchstructure(stream, stream->nmsgs, &body)){
212 fprintf(stderr, "Can't access remote IMAP data\n");
213 mail_close(stream);
214 exit(-1);
217 if(!body ||
218 body->type != REMOTE_DATA_TYPE ||
219 !body->subtype ||
220 (!force && strucmp(body->subtype, spechdr(rtype)))){
221 fprintf(stderr, "Remote IMAP folder has wrong contents\n");
222 mail_close(stream);
223 exit(-1);
226 if(!mail_fetchenvelope(stream, stream->nmsgs)){
227 fprintf(stderr, "Can't access envelope in remote data\n");
228 mail_close(stream);
229 exit(-1);
232 data = mail_fetch_body(stream, stream->nmsgs, "1", &i, FT_PEEK);
234 p = data;
235 for(p = data; p < data+i; p++){
237 /* convert to unix newlines */
238 if(*p == '\r' && *(p+1) == '\n')
239 p++;
241 if(putc(*p, fp) == EOF){
242 fprintf(stderr,
243 "Error writing \"%s\": %s\n", local, err_desc(errno));
244 fclose(fp);
245 mail_close(stream);
246 exit(-1);
250 mail_close(stream);
251 fclose(fp);
253 fprintf(stderr,
254 "Remote folder is of type \"%s\", contents saved to \"%s\"\n",
255 ptype(rtype) ? ptype(rtype) : "unknown", local);
256 exit(0);
260 RemoteType
261 check_for_header_msg(stream)
262 MAILSTREAM *stream;
264 STRINGLIST *sl;
265 int ret = NotSet;
266 char *h, *try;
267 size_t len;
268 char *pinerc, *abook, *sig, *smime;
270 pinerc = spechdr(Pinerc);
271 abook = spechdr(Abook);
272 sig = spechdr(Sig);
273 smime = spechdr(Smime);
275 len = MAX(MAX(strlen(pinerc), strlen(abook)), MAX(strlen(sig), strlen(smime)));
277 sl = mail_newstringlist();
278 sl->text.data = (unsigned char *)fs_get((len+1) * sizeof(unsigned char));
279 try = pinerc;
280 strncpy((char *) sl->text.data, try, len);
281 sl->text.data[len] = '\0';
282 sl->text.size = strlen((char *) sl->text.data);
284 if(stream && (h=mail_fetch_header(stream,1L,NULL,sl,NULL,FT_PEEK))){
286 if(strlen(h) >= sl->text.size && !struncmp(h, try, sl->text.size))
287 ret = Pinerc;
290 if(ret == NotSet){
291 try = abook;
292 strncpy((char *)sl->text.data, try, len);
293 sl->text.data[len] = '\0';
294 sl->text.size = strlen((char *) sl->text.data);
295 if(stream && (h=mail_fetch_header(stream,1L,NULL,sl,NULL,FT_PEEK))){
297 if(strlen(h) >= sl->text.size && !struncmp(h, try, sl->text.size))
298 ret = Abook;
302 if(ret == NotSet){
303 try = sig;
304 strncpy((char *) sl->text.data, try, len);
305 sl->text.data[len] = '\0';
306 sl->text.size = strlen((char *) sl->text.data);
307 if(stream && (h=mail_fetch_header(stream,1L,NULL,sl,NULL,FT_PEEK))){
309 if(strlen(h) >= sl->text.size && !struncmp(h, try, sl->text.size))
310 ret = Sig;
314 if(sl)
315 mail_free_stringlist(&sl);
317 if(pinerc)
318 fs_give((void **)&pinerc);
319 if(abook)
320 fs_give((void **)&abook);
321 if(sig)
322 fs_give((void **)&sig);
323 if(smime)
324 fs_give((void **)&smime);
326 return(ret);
330 char *
331 ptype(rtype)
332 RemoteType rtype;
334 char *ret = NULL;
336 switch(rtype){
337 case Pinerc:
338 ret = cpystr("pinerc");
339 break;
340 case Abook:
341 ret = cpystr("abook");
342 break;
343 case Sig:
344 ret = cpystr("sig");
345 break;
346 case Smime:
347 ret = cpystr("smime");
348 break;
349 default:
350 break;
353 return(ret);
357 char *
358 spechdr(rtype)
359 RemoteType rtype;
361 char *ret = NULL;
363 switch(rtype){
364 case Pinerc:
365 ret = cpystr(REMOTE_PINERC_SUBTYPE);
366 break;
367 case Abook:
368 ret = cpystr(REMOTE_ABOOK_SUBTYPE);
369 break;
370 case Sig:
371 ret = cpystr(REMOTE_SIG_SUBTYPE);
372 break;
373 case Smime:
374 ret = cpystr(REMOTE_SMIME_SUBTYPE);
375 break;
376 default:
377 break;
380 return(ret);
385 parse_args(argc, argv, force, local, remote)
386 int argc;
387 char **argv;
388 int *force;
389 char **local, **remote;
391 int ac;
392 char **av;
393 int c;
394 char *str;
395 int usage = 0;
397 ac = argc;
398 av = argv;
400 /* while more arguments with leading - */
401 Loop: while(--ac > 0 && **++av == '-'){
402 /* while more chars in this argument */
403 while(*++*av){
404 switch(c = **av){
405 case 'h':
406 usage++;
407 break;
408 case 'f':
409 (*force)++;
410 break;
412 case 'r': case 'l': /* string args */
413 if(*++*av)
414 str = *av;
415 else if(--ac)
416 str = *++av;
417 else{
418 fprintf(stderr, "missing argument for flag \"%c\"\n", c);
419 ++usage;
420 goto Loop;
423 switch(c){
424 case 'l':
425 if(str)
426 *local = str;
428 break;
429 case 'r':
430 if(str)
431 *remote = str;
433 break;
436 goto Loop;
438 default:
439 fprintf(stderr, "unknown flag \"%c\"\n", c);
440 ++usage;
441 break;
446 if(ac != 0)
447 usage++;
449 return(usage);
453 char *
454 err_desc(err)
455 int err;
457 return((char *) strerror(err));
461 void mm_exists(stream, number)
462 MAILSTREAM *stream;
463 unsigned long number;
468 void mm_expunged(stream, number)
469 MAILSTREAM *stream;
470 unsigned long number;
475 void mm_flags(stream, number)
476 MAILSTREAM *stream;
477 unsigned long number;
482 void mm_list(stream, delim, name, attrib)
483 MAILSTREAM *stream;
484 int delim;
485 char *name;
486 long attrib;
491 void mm_lsub(stream, delimiter, name, attributes)
492 MAILSTREAM *stream;
493 int delimiter;
494 char *name;
495 long attributes;
500 void mm_notify(stream, string, errflg)
501 MAILSTREAM *stream;
502 char *string;
503 long errflg;
505 mm_log(string, errflg);
509 void mm_log(string, errflg)
510 char *string;
511 long errflg;
513 if(noshow_error)
514 return;
516 switch(errflg){
517 case BYE:
518 case NIL:
519 break;
521 case PARSE:
522 fprintf(stderr, "PARSE: %s\n", string);
523 break;
525 case WARN:
526 fprintf(stderr, "WARN: %s\n", string);
527 break;
529 case ERROR:
530 fprintf(stderr, "ERROR: %s\n", string);
531 break;
533 default:
534 fprintf(stderr, "%s\n", string);
535 break;
539 void mm_login_method(mb, user, pwd, trial, method)
540 NETMBX *mb;
541 char *user;
542 void *pwd;
543 long trial;
544 char *method;
546 mm_login(mb, user, (char **) pwd, trial);
549 void mm_login(mb, user, pwd, trial)
550 NETMBX *mb;
551 char *user;
552 char **pwd;
553 long trial;
555 char prompt[100], *last, tmp[MAILTMPLEN];
556 int i, j, goal, ugoal, len, rc, flags = 0;
557 #define NETMAXPASSWD 100
559 user[NETMAXUSER-1] = '\0';
561 if(trial == 0L){
562 if(mb->user && *mb->user){
563 strncpy(user, mb->user, NETMAXUSER);
564 user[NETMAXUSER-1] = '\0';
568 if(!*mb->user){
569 /* Dress up long hostnames */
570 snprintf(prompt, sizeof(prompt), "%sHOST: ",
571 (mb->sslflag||mb->tlsflag) ? "+ " : "");
572 len = strlen(prompt);
573 /* leave space for "HOST", "ENTER NAME", and 15 chars for input name */
574 goal = 80 - (len + 20 + MIN(15, 80/5));
575 last = " ENTER LOGIN NAME: ";
576 if(goal < 9){
577 last = " LOGIN: ";
578 if((goal += 13) < 9){
579 last += 1;
580 goal = 0;
584 if(goal){
585 for(i = len, j = 0;
586 i < sizeof(prompt) && (prompt[i] = mb->host[j]); i++, j++)
587 if(i == goal && mb->host[goal+1] && i < sizeof(prompt)){
588 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
589 prompt[sizeof(prompt)-1] = '\0';
590 break;
593 else
594 i = 0;
596 strncpy(&prompt[i], last, sizeof(prompt)-i);
597 prompt[sizeof(prompt)-1] = '\0';
599 while(1) {
600 rc = opt_enter(user, NETMAXUSER, prompt, &flags);
601 if(rc != 4)
602 break;
605 if(rc == 1 || !user[0]) {
606 user[0] = '\0';
607 *pwd = NULL;
610 else
611 strncpy(user, mb->user, NETMAXUSER);
613 user[NETMAXUSER-1] = '\0';
614 // pwd[NETMAXPASSWD-1] = '\0';
616 if(!user[0])
617 return;
620 /* Dress up long host/user names */
621 /* leave space for "HOST", "USER" "ENTER PWD", 12 for user 6 for pwd */
622 snprintf(prompt, sizeof(prompt), "%sHOST: ", (mb->sslflag||mb->tlsflag) ? "+ " : "");
623 len = strlen(prompt);
624 goal = strlen(mb->host);
625 ugoal = strlen(user);
626 if((i = 80 - (len + 8 + 18 + 6)) < 14){
627 goal = 0; /* no host! */
628 if((i = 80 - (6 + 18 + 6)) <= 6){
629 ugoal = 0; /* no user! */
630 if((i = 80 - (18 + 6)) <= 0)
631 i = 0;
633 else{
634 ugoal = i; /* whatever's left */
635 i = 0;
638 else
639 while(goal + ugoal > i)
640 if(goal > ugoal)
641 goal--;
642 else
643 ugoal--;
645 if(goal){
646 snprintf(prompt, sizeof(prompt), "%sHOST: ",
647 (mb->sslflag||mb->tlsflag) ? "+ " : "");
648 for(i = len, j = 0;
649 i < sizeof(prompt) && (prompt[i] = mb->host[j]); i++, j++)
650 if(i == goal && mb->host[goal+1] && i < sizeof(prompt)){
651 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
652 prompt[sizeof(prompt)-1] = '\0';
653 break;
656 else
657 i = 0;
659 if(ugoal){
660 strncpy(&prompt[i], &" USER: "[i ? 0 : 2], sizeof(prompt)-i);
661 prompt[sizeof(prompt)-1] = '\0';
662 for(i += strlen(&prompt[i]), j = 0;
663 i < sizeof(prompt) && (prompt[i] = user[j]); i++, j++)
664 if(j == ugoal && user[ugoal+1] && i < sizeof(prompt)){
665 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
666 prompt[sizeof(prompt)-1] = '\0';
667 break;
671 strncpy(&prompt[i], &" ENTER PASSWORD: "[i ? 0 : 8], sizeof(prompt)-i);
672 prompt[sizeof(prompt)-1] = '\0';
674 tmp[0] = '\0';
675 while(1) {
676 flags = OE_PASSWD;
677 rc = opt_enter(tmp, NETMAXPASSWD, prompt, &flags);
678 if(rc != 4)
679 break;
682 if(tmp[0]) *pwd = cpystr(tmp);
683 if(rc == 1 || !tmp[0]) {
684 user[0] = '\0';
685 return;
690 void mm_critical(stream)
691 MAILSTREAM *stream;
696 void mm_nocritical(stream)
697 MAILSTREAM *stream;
702 long mm_diskerror(stream, errcode, serious)
703 MAILSTREAM *stream;
704 long errcode;
705 long serious;
707 return T;
711 void mm_fatal(string)
712 char *string;
714 fprintf(stderr, "%s\n", string);
718 void mm_searched(stream, msgno)
719 MAILSTREAM *stream;
720 unsigned long msgno;
725 void mm_status(stream, mailbox, status)
726 MAILSTREAM *stream;
727 char *mailbox;
728 MAILSTATUS *status;
732 void mm_dlog(string)
733 char *string;
735 fprintf(stderr, "%s\n", string);
740 opt_enter(string, field_len, prompt, flags)
741 char *string, *prompt;
742 int field_len;
743 int *flags;
745 char *pw;
746 int return_v = -10;
748 while(return_v == -10){
750 if(flags && *flags & OE_PASSWD){
751 if((pw = getpass(prompt)) != NULL){
752 if(strlen(pw) < field_len){
753 strncpy(string, pw, field_len);
754 string[field_len-1] = '\0';
755 return_v = 0;
757 else{
758 fputs("Password too long\n", stderr);
759 return_v = -1;
762 else
763 return_v = 1; /* cancel? */
765 else{
766 char *p;
768 fputs(prompt, stdout);
769 fgets(string, field_len, stdin);
770 string[field_len-1] = '\0';
771 if((p = strpbrk(string, "\r\n")) != NULL)
772 *p = '\0';
774 return_v = 0;
778 return(return_v);
781 char *
782 last_cmpnt(filename)
783 char *filename;
785 register char *p = NULL, *q = filename;
787 if(!q)
788 return(q);
790 while((q = strchr(q, '/')) != NULL)
791 if(*++q)
792 p = q;
794 return(p);
798 wantto(question, dflt, on_ctrl_C)
799 char *question;
800 int dflt, on_ctrl_C;
802 int ret = 0;
803 char rep[1000], *p;
805 while(!ret){
806 fprintf(stdout, "%s? [%c]:", question, dflt);
807 fgets(rep, sizeof(rep), stdin);
808 if((p = strpbrk(rep, "\r\n")) != NULL)
809 *p = '\0';
810 switch(*rep){
811 case 'Y':
812 case 'y':
813 ret = (int)'y';
814 break;
815 case 'N':
816 case 'n':
817 ret = (int)'n';
818 break;
819 case '\0':
820 ret = dflt;
821 break;
822 default:
823 break;
827 return ret;