1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: rpdump.c 1074 2008-06-04 00:08:43Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2013-2017 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 * ========================================================================
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
);
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";
41 /* look for my_timer_period in pico directory for an explanation */
42 int my_timer_period
= ((IDLE_TIMEOUT
+ 1)*1000);
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.
70 MAILSTREAM
*stream
= NULL
;
74 char *local
= NULL
, *remote
= NULL
;
82 #include "../c-client/linkage.c"
84 if(parse_args(argc
, argv
, &force
, &local
, &remote
)){
85 fprintf(stderr
, ustr
, argv
[0]);
89 if(!local
|| !*local
){
90 fprintf(stderr
, "No local file specified\n");
94 if(!remote
|| !*remote
){
95 fprintf(stderr
, "No remote folder specified\n");
100 fprintf(stderr
, ustr
, argv
[0]);
104 if(!IS_REMOTE(remote
)){
106 "Remote folder name \"%s\" %s\n", remote
,
107 (*remote
!= '{') ? "must begin with \"{\"" : "not valid");
111 if(IS_REMOTE(local
)){
112 fprintf(stderr
, "Argument to -l (%s) must be a local filename", local
);
117 if(stat(local
, &sbuf
))
119 if(lstat(local
, &sbuf
))
122 if(errno
== ENOENT
){ /* File did not exist */
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
));
134 else{ /* unknown error */
135 fprintf(stderr
, "%s: %s\n", local
, err_desc(errno
));
139 else{ /* file exists */
141 /* is it a regular file? */
143 if(!S_ISREG(sbuf
.st_mode
))
145 if(!(S_IFREG
& sbuf
.st_mode
))
148 fprintf(stderr
, "Only allowed to write to regular local files. Try another filename.\n");
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");
162 fprintf(stderr
, "Local file \"%s\" is not writable\n", local
);
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
));
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
);
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
);
200 else if(stream
->nmsgs
== 1){
201 fprintf(stderr
, "No data in remote folder to copy (only 1 message)\n");
206 fprintf(stderr
, "No data in remote folder to copy\n");
211 if(!mail_fetchstructure(stream
, stream
->nmsgs
, &body
)){
212 fprintf(stderr
, "Can't access remote IMAP data\n");
218 body
->type
!= REMOTE_DATA_TYPE
||
220 (!force
&& strucmp(body
->subtype
, spechdr(rtype
)))){
221 fprintf(stderr
, "Remote IMAP folder has wrong contents\n");
226 if(!mail_fetchenvelope(stream
, stream
->nmsgs
)){
227 fprintf(stderr
, "Can't access envelope in remote data\n");
232 data
= mail_fetch_body(stream
, stream
->nmsgs
, "1", &i
, FT_PEEK
);
235 for(p
= data
; p
< data
+i
; p
++){
237 /* convert to unix newlines */
238 if(*p
== '\r' && *(p
+1) == '\n')
241 if(putc(*p
, fp
) == EOF
){
243 "Error writing \"%s\": %s\n", local
, err_desc(errno
));
254 "Remote folder is of type \"%s\", contents saved to \"%s\"\n",
255 ptype(rtype
) ? ptype(rtype
) : "unknown", local
);
261 check_for_header_msg(stream
)
268 char *pinerc
, *abook
, *sig
, *smime
;
270 pinerc
= spechdr(Pinerc
);
271 abook
= spechdr(Abook
);
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));
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
))
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
))
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
))
315 mail_free_stringlist(&sl
);
318 fs_give((void **)&pinerc
);
320 fs_give((void **)&abook
);
322 fs_give((void **)&sig
);
324 fs_give((void **)&smime
);
338 ret
= cpystr("pinerc");
341 ret
= cpystr("abook");
347 ret
= cpystr("smime");
365 ret
= cpystr(REMOTE_PINERC_SUBTYPE
);
368 ret
= cpystr(REMOTE_ABOOK_SUBTYPE
);
371 ret
= cpystr(REMOTE_SIG_SUBTYPE
);
374 ret
= cpystr(REMOTE_SMIME_SUBTYPE
);
385 parse_args(argc
, argv
, force
, local
, remote
)
389 char **local
, **remote
;
400 /* while more arguments with leading - */
401 Loop
: while(--ac
> 0 && **++av
== '-'){
402 /* while more chars in this argument */
412 case 'r': case 'l': /* string args */
418 fprintf(stderr
, "missing argument for flag \"%c\"\n", c
);
439 fprintf(stderr
, "unknown flag \"%c\"\n", c
);
457 return((char *) strerror(err
));
461 void mm_exists(stream
, number
)
463 unsigned long number
;
468 void mm_expunged(stream
, number
)
470 unsigned long number
;
475 void mm_flags(stream
, number
)
477 unsigned long number
;
482 void mm_list(stream
, delim
, name
, attrib
)
491 void mm_lsub(stream
, delimiter
, name
, attributes
)
500 void mm_notify(stream
, string
, errflg
)
505 mm_log(string
, errflg
);
509 void mm_log(string
, errflg
)
522 fprintf(stderr
, "PARSE: %s\n", string
);
526 fprintf(stderr
, "WARN: %s\n", string
);
530 fprintf(stderr
, "ERROR: %s\n", string
);
534 fprintf(stderr
, "%s\n", string
);
540 void mm_login(mb
, user
, pwd
, trial
)
546 char prompt
[100], *last
;
547 int i
, j
, goal
, ugoal
, len
, rc
, flags
= 0;
548 #define NETMAXPASSWD 100
550 user
[NETMAXUSER
-1] = '\0';
553 if(mb
->user
&& *mb
->user
){
554 strncpy(user
, mb
->user
, NETMAXUSER
);
555 user
[NETMAXUSER
-1] = '\0';
560 /* Dress up long hostnames */
561 snprintf(prompt
, sizeof(prompt
), "%sHOST: ",
562 (mb
->sslflag
||mb
->tlsflag
) ? "+ " : "");
563 len
= strlen(prompt
);
564 /* leave space for "HOST", "ENTER NAME", and 15 chars for input name */
565 goal
= 80 - (len
+ 20 + MIN(15, 80/5));
566 last
= " ENTER LOGIN NAME: ";
569 if((goal
+= 13) < 9){
577 i
< sizeof(prompt
) && (prompt
[i
] = mb
->host
[j
]); i
++, j
++)
578 if(i
== goal
&& mb
->host
[goal
+1] && i
< sizeof(prompt
)){
579 strncpy(&prompt
[i
-3], "...", sizeof(prompt
)-(i
-3));
580 prompt
[sizeof(prompt
)-1] = '\0';
587 strncpy(&prompt
[i
], last
, sizeof(prompt
)-i
);
588 prompt
[sizeof(prompt
)-1] = '\0';
591 rc
= opt_enter(user
, NETMAXUSER
, prompt
, &flags
);
596 if(rc
== 1 || !user
[0]) {
602 strncpy(user
, mb
->user
, NETMAXUSER
);
604 user
[NETMAXUSER
-1] = '\0';
605 pwd
[NETMAXPASSWD
-1] = '\0';
611 /* Dress up long host/user names */
612 /* leave space for "HOST", "USER" "ENTER PWD", 12 for user 6 for pwd */
613 snprintf(prompt
, sizeof(prompt
), "%sHOST: ", (mb
->sslflag
||mb
->tlsflag
) ? "+ " : "");
614 len
= strlen(prompt
);
615 goal
= strlen(mb
->host
);
616 ugoal
= strlen(user
);
617 if((i
= 80 - (len
+ 8 + 18 + 6)) < 14){
618 goal
= 0; /* no host! */
619 if((i
= 80 - (6 + 18 + 6)) <= 6){
620 ugoal
= 0; /* no user! */
621 if((i
= 80 - (18 + 6)) <= 0)
625 ugoal
= i
; /* whatever's left */
630 while(goal
+ ugoal
> i
)
637 snprintf(prompt
, sizeof(prompt
), "%sHOST: ",
638 (mb
->sslflag
||mb
->tlsflag
) ? "+ " : "");
640 i
< sizeof(prompt
) && (prompt
[i
] = mb
->host
[j
]); i
++, j
++)
641 if(i
== goal
&& mb
->host
[goal
+1] && i
< sizeof(prompt
)){
642 strncpy(&prompt
[i
-3], "...", sizeof(prompt
)-(i
-3));
643 prompt
[sizeof(prompt
)-1] = '\0';
651 strncpy(&prompt
[i
], &" USER: "[i
? 0 : 2], sizeof(prompt
)-i
);
652 prompt
[sizeof(prompt
)-1] = '\0';
653 for(i
+= strlen(&prompt
[i
]), j
= 0;
654 i
< sizeof(prompt
) && (prompt
[i
] = user
[j
]); i
++, j
++)
655 if(j
== ugoal
&& user
[ugoal
+1] && i
< sizeof(prompt
)){
656 strncpy(&prompt
[i
-3], "...", sizeof(prompt
)-(i
-3));
657 prompt
[sizeof(prompt
)-1] = '\0';
662 strncpy(&prompt
[i
], &" ENTER PASSWORD: "[i
? 0 : 8], sizeof(prompt
)-i
);
663 prompt
[sizeof(prompt
)-1] = '\0';
668 rc
= opt_enter(pwd
, NETMAXPASSWD
, prompt
, &flags
);
673 if(rc
== 1 || !pwd
[0]) {
674 user
[0] = pwd
[0] = '\0';
680 void mm_critical(stream
)
686 void mm_nocritical(stream
)
692 long mm_diskerror(stream
, errcode
, serious
)
701 void mm_fatal(string
)
704 fprintf(stderr
, "%s\n", string
);
708 void mm_searched(stream
, msgno
)
715 void mm_status(stream
, mailbox
, status
)
725 fprintf(stderr
, "%s\n", string
);
730 opt_enter(string
, field_len
, prompt
, flags
)
731 char *string
, *prompt
;
738 while(return_v
== -10){
740 if(flags
&& *flags
& OE_PASSWD
){
741 if((pw
= getpass(prompt
)) != NULL
){
742 if(strlen(pw
) < field_len
){
743 strncpy(string
, pw
, field_len
);
744 string
[field_len
-1] = '\0';
748 fputs("Password too long\n", stderr
);
753 return_v
= 1; /* cancel? */
758 fputs(prompt
, stdout
);
759 fgets(string
, field_len
, stdin
);
760 string
[field_len
-1] = '\0';
761 if((p
= strpbrk(string
, "\r\n")) != NULL
)
775 register char *p
= NULL
, *q
= filename
;
780 while((q
= strchr(q
, '/')) != NULL
)
788 wantto(question
, dflt
, on_ctrl_C
)
796 fprintf(stdout
, "%s? [%c]:", question
, dflt
);
797 fgets(rep
, sizeof(rep
), stdin
);
798 if((p
= strpbrk(rep
, "\r\n")) != NULL
)