2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2008 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
16 #include "radio.h" /* OE_PASSWD */
17 #include "../pith/util.h" /* IS_REMOTE() */
18 #include "../pith/remote.h" /* REMOTE_ABOOK_SUBTYPE... */
21 typedef enum {Pinerc
, Abook
, Sig
, Smime
, NotSet
} RemoteType
;
24 int parse_args(int, char **, int *, char **, char **);
25 RemoteType
check_for_header_msg(MAILSTREAM
*);
26 char *ptype(RemoteType
);
27 char *spechdr(RemoteType
);
29 int opt_enter(char *, int, char *, int *);
30 char *last_cmpnt(char *);
31 int wantto(char *, int, int);
34 char *ustr
= "usage: %s [-f] -l Local_file -r Remote_folder\n";
37 /* look for my_timer_period in pico directory for an explanation */
38 int my_timer_period
= ((IDLE_TIMEOUT
+ 1)*1000);
55 * rpdump [-f] -l Local_file -r Remote_folder
57 * -f (skip check for special header)
59 * Note: We're not worrying about memory leaks.
66 MAILSTREAM
*stream
= NULL
;
70 char *local
= NULL
, *remote
= NULL
;
78 #include "../c-client/linkage.c"
80 if(parse_args(argc
, argv
, &force
, &local
, &remote
)){
81 fprintf(stderr
, ustr
, argv
[0]);
85 if(!local
|| !*local
){
86 fprintf(stderr
, "No local file specified\n");
90 if(!remote
|| !*remote
){
91 fprintf(stderr
, "No remote folder specified\n");
96 fprintf(stderr
, ustr
, argv
[0]);
100 if(!IS_REMOTE(remote
)){
102 "Remote folder name \"%s\" %s\n", remote
,
103 (*remote
!= '{') ? "must begin with \"{\"" : "not valid");
107 if(IS_REMOTE(local
)){
108 fprintf(stderr
, "Argument to -l (%s) must be a local filename", local
);
113 if(stat(local
, &sbuf
))
115 if(lstat(local
, &sbuf
))
118 if(errno
== ENOENT
){ /* File did not exist */
122 if(((fd
= open(local
, O_CREAT
|O_EXCL
|O_WRONLY
,0600)) < 0)
123 || (close(fd
) != 0)){
124 fprintf(stderr
, "%s: %s\n", local
, err_desc(errno
));
130 else{ /* unknown error */
131 fprintf(stderr
, "%s: %s\n", local
, err_desc(errno
));
135 else{ /* file exists */
137 /* is it a regular file? */
139 if(!S_ISREG(sbuf
.st_mode
))
141 if(!(S_IFREG
& sbuf
.st_mode
))
144 fprintf(stderr
, "Only allowed to write to regular local files. Try another filename.\n");
148 if(access(local
, WRITE_ACCESS
) == 0){
150 snprintf(buf
, sizeof(buf
), "Local file \"%s\" exists, overwrite it",
151 (p
= last_cmpnt(local
)) ? p
: local
);
152 if(wantto(buf
, 'n', 'n') != 'y'){
153 fprintf(stderr
, "Dump cancelled\n");
158 fprintf(stderr
, "Local file \"%s\" is not writable\n", local
);
164 * Try opening the local file.
166 if((fp
= fopen(local
, "w")) == NULL
){
167 fprintf(stderr
, "Can't open \"%s\": %s\n", local
, err_desc(errno
));
173 * Try opening the remote folder.
175 stream
= mail_open(NULL
, remote
, OP_READONLY
);
176 if(!stream
|| stream
->halfopen
){
177 fprintf(stderr
, "Remote folder \"%s\" is not readable\n", remote
);
184 if(stream
->nmsgs
>= 2){
186 * There is a first message already. Check to see if it is one of
187 * our special header messages.
189 rtype
= check_for_header_msg(stream
);
190 if(!force
&& rtype
== NotSet
){
191 fprintf(stderr
, "Folder \"%s\"\ndoes not appear to be an Alpine remote data folder.\nUse -f to force.\n", remote
);
196 else if(stream
->nmsgs
== 1){
197 fprintf(stderr
, "No data in remote folder to copy (only 1 message)\n");
202 fprintf(stderr
, "No data in remote folder to copy\n");
207 if(!mail_fetchstructure(stream
, stream
->nmsgs
, &body
)){
208 fprintf(stderr
, "Can't access remote IMAP data\n");
214 body
->type
!= REMOTE_DATA_TYPE
||
216 (!force
&& strucmp(body
->subtype
, spechdr(rtype
)))){
217 fprintf(stderr
, "Remote IMAP folder has wrong contents\n");
222 if(!mail_fetchenvelope(stream
, stream
->nmsgs
)){
223 fprintf(stderr
, "Can't access envelope in remote data\n");
228 data
= mail_fetch_body(stream
, stream
->nmsgs
, "1", &i
, FT_PEEK
);
231 for(p
= data
; p
< data
+i
; p
++){
233 /* convert to unix newlines */
234 if(*p
== '\r' && *(p
+1) == '\n')
237 if(putc(*p
, fp
) == EOF
){
239 "Error writing \"%s\": %s\n", local
, err_desc(errno
));
250 "Remote folder is of type \"%s\", contents saved to \"%s\"\n",
251 ptype(rtype
) ? ptype(rtype
) : "unknown", local
);
257 check_for_header_msg(stream
)
264 char *pinerc
, *abook
, *sig
, *smime
;
266 pinerc
= spechdr(Pinerc
);
267 abook
= spechdr(Abook
);
269 smime
= spechdr(Smime
);
271 len
= MAX(MAX(strlen(pinerc
), strlen(abook
)), MAX(strlen(sig
), strlen(smime
)));
273 sl
= mail_newstringlist();
274 sl
->text
.data
= (unsigned char *)fs_get((len
+1) * sizeof(unsigned char));
276 strncpy((char *) sl
->text
.data
, try, len
);
277 sl
->text
.data
[len
] = '\0';
278 sl
->text
.size
= strlen((char *) sl
->text
.data
);
280 if(stream
&& (h
=mail_fetch_header(stream
,1L,NULL
,sl
,NULL
,FT_PEEK
))){
282 if(strlen(h
) >= sl
->text
.size
&& !struncmp(h
, try, sl
->text
.size
))
288 strncpy((char *)sl
->text
.data
, try, len
);
289 sl
->text
.data
[len
] = '\0';
290 sl
->text
.size
= strlen((char *) sl
->text
.data
);
291 if(stream
&& (h
=mail_fetch_header(stream
,1L,NULL
,sl
,NULL
,FT_PEEK
))){
293 if(strlen(h
) >= sl
->text
.size
&& !struncmp(h
, try, sl
->text
.size
))
300 strncpy((char *) sl
->text
.data
, try, len
);
301 sl
->text
.data
[len
] = '\0';
302 sl
->text
.size
= strlen((char *) sl
->text
.data
);
303 if(stream
&& (h
=mail_fetch_header(stream
,1L,NULL
,sl
,NULL
,FT_PEEK
))){
305 if(strlen(h
) >= sl
->text
.size
&& !struncmp(h
, try, sl
->text
.size
))
311 mail_free_stringlist(&sl
);
314 fs_give((void **)&pinerc
);
316 fs_give((void **)&abook
);
318 fs_give((void **)&sig
);
320 fs_give((void **)&smime
);
334 ret
= cpystr("pinerc");
337 ret
= cpystr("abook");
343 ret
= cpystr("smime");
361 ret
= cpystr(REMOTE_PINERC_SUBTYPE
);
364 ret
= cpystr(REMOTE_ABOOK_SUBTYPE
);
367 ret
= cpystr(REMOTE_SIG_SUBTYPE
);
370 ret
= cpystr(REMOTE_SMIME_SUBTYPE
);
381 parse_args(argc
, argv
, force
, local
, remote
)
385 char **local
, **remote
;
396 /* while more arguments with leading - */
397 Loop
: while(--ac
> 0 && **++av
== '-'){
398 /* while more chars in this argument */
408 case 'r': case 'l': /* string args */
414 fprintf(stderr
, "missing argument for flag \"%c\"\n", c
);
435 fprintf(stderr
, "unknown flag \"%c\"\n", c
);
453 return((char *) strerror(err
));
457 void mm_exists(stream
, number
)
459 unsigned long number
;
464 void mm_expunged(stream
, number
)
466 unsigned long number
;
471 void mm_flags(stream
, number
)
473 unsigned long number
;
478 void mm_list(stream
, delim
, name
, attrib
)
487 void mm_lsub(stream
, delimiter
, name
, attributes
)
496 void mm_notify(stream
, string
, errflg
)
501 mm_log(string
, errflg
);
505 void mm_log(string
, errflg
)
518 fprintf(stderr
, "PARSE: %s\n", string
);
522 fprintf(stderr
, "WARN: %s\n", string
);
526 fprintf(stderr
, "ERROR: %s\n", string
);
530 fprintf(stderr
, "%s\n", string
);
535 void mm_login_method(mb
, user
, pwd
, trial
, method
)
542 mm_login(mb
, user
, (char **) pwd
, trial
);
545 void mm_login(mb
, user
, pwd
, trial
)
551 char prompt
[100], *last
, tmp
[MAILTMPLEN
];
552 int i
, j
, goal
, ugoal
, len
, rc
, flags
= 0;
553 #define NETMAXPASSWD 100
555 user
[NETMAXUSER
-1] = '\0';
558 if(mb
->user
&& *mb
->user
){
559 strncpy(user
, mb
->user
, NETMAXUSER
);
560 user
[NETMAXUSER
-1] = '\0';
565 /* Dress up long hostnames */
566 snprintf(prompt
, sizeof(prompt
), "%sHOST: ",
567 (mb
->sslflag
||mb
->tlsflag
) ? "+ " : "");
568 len
= strlen(prompt
);
569 /* leave space for "HOST", "ENTER NAME", and 15 chars for input name */
570 goal
= 80 - (len
+ 20 + MIN(15, 80/5));
571 last
= " ENTER LOGIN NAME: ";
574 if((goal
+= 13) < 9){
582 i
< sizeof(prompt
) && (prompt
[i
] = mb
->host
[j
]); i
++, j
++)
583 if(i
== goal
&& mb
->host
[goal
+1] && i
< sizeof(prompt
)){
584 strncpy(&prompt
[i
-3], "...", sizeof(prompt
)-(i
-3));
585 prompt
[sizeof(prompt
)-1] = '\0';
592 strncpy(&prompt
[i
], last
, sizeof(prompt
)-i
);
593 prompt
[sizeof(prompt
)-1] = '\0';
596 rc
= opt_enter(user
, NETMAXUSER
, prompt
, &flags
);
601 if(rc
== 1 || !user
[0]) {
607 strncpy(user
, mb
->user
, NETMAXUSER
);
609 user
[NETMAXUSER
-1] = '\0';
610 // pwd[NETMAXPASSWD-1] = '\0';
616 /* Dress up long host/user names */
617 /* leave space for "HOST", "USER" "ENTER PWD", 12 for user 6 for pwd */
618 snprintf(prompt
, sizeof(prompt
), "%sHOST: ", (mb
->sslflag
||mb
->tlsflag
) ? "+ " : "");
619 len
= strlen(prompt
);
620 goal
= strlen(mb
->host
);
621 ugoal
= strlen(user
);
622 if((i
= 80 - (len
+ 8 + 18 + 6)) < 14){
623 goal
= 0; /* no host! */
624 if((i
= 80 - (6 + 18 + 6)) <= 6){
625 ugoal
= 0; /* no user! */
626 if((i
= 80 - (18 + 6)) <= 0)
630 ugoal
= i
; /* whatever's left */
635 while(goal
+ ugoal
> i
)
642 snprintf(prompt
, sizeof(prompt
), "%sHOST: ",
643 (mb
->sslflag
||mb
->tlsflag
) ? "+ " : "");
645 i
< sizeof(prompt
) && (prompt
[i
] = mb
->host
[j
]); i
++, j
++)
646 if(i
== goal
&& mb
->host
[goal
+1] && i
< sizeof(prompt
)){
647 strncpy(&prompt
[i
-3], "...", sizeof(prompt
)-(i
-3));
648 prompt
[sizeof(prompt
)-1] = '\0';
656 strncpy(&prompt
[i
], &" USER: "[i
? 0 : 2], sizeof(prompt
)-i
);
657 prompt
[sizeof(prompt
)-1] = '\0';
658 for(i
+= strlen(&prompt
[i
]), j
= 0;
659 i
< sizeof(prompt
) && (prompt
[i
] = user
[j
]); i
++, j
++)
660 if(j
== ugoal
&& user
[ugoal
+1] && i
< sizeof(prompt
)){
661 strncpy(&prompt
[i
-3], "...", sizeof(prompt
)-(i
-3));
662 prompt
[sizeof(prompt
)-1] = '\0';
667 strncpy(&prompt
[i
], &" ENTER PASSWORD: "[i
? 0 : 8], sizeof(prompt
)-i
);
668 prompt
[sizeof(prompt
)-1] = '\0';
673 rc
= opt_enter(tmp
, NETMAXPASSWD
, prompt
, &flags
);
678 if(tmp
[0]) *pwd
= cpystr(tmp
);
679 if(rc
== 1 || !tmp
[0]) {
686 void mm_critical(stream
)
692 void mm_nocritical(stream
)
698 long mm_diskerror(stream
, errcode
, serious
)
707 void mm_fatal(string
)
710 fprintf(stderr
, "%s\n", string
);
714 void mm_searched(stream
, msgno
)
721 void mm_status(stream
, mailbox
, status
)
731 fprintf(stderr
, "%s\n", string
);
736 opt_enter(string
, field_len
, prompt
, flags
)
737 char *string
, *prompt
;
744 while(return_v
== -10){
746 if(flags
&& *flags
& OE_PASSWD
){
747 if((pw
= getpass(prompt
)) != NULL
){
748 if(strlen(pw
) < field_len
){
749 strncpy(string
, pw
, field_len
);
750 string
[field_len
-1] = '\0';
754 fputs("Password too long\n", stderr
);
759 return_v
= 1; /* cancel? */
764 fputs(prompt
, stdout
);
765 if(!fgets(string
, field_len
, stdin
))
766 return_v
= 1; /* cancel? */
767 string
[field_len
-1] = '\0';
768 if((p
= strpbrk(string
, "\r\n")) != NULL
)
782 register char *p
= NULL
, *q
= filename
;
787 while((q
= strchr(q
, '/')) != NULL
)
795 wantto(question
, dflt
, on_ctrl_C
)
803 fprintf(stdout
, "%s? [%c]:", question
, dflt
);
804 if(!fgets(rep
, sizeof(rep
), stdin
))
806 if((p
= strpbrk(rep
, "\r\n")) != NULL
)