* Fix some compiler warnings for bad casting in some functions in the file
[alpine.git] / alpine / rpload.c
blob9f53b5037fa2479e9fcaee2531510055cdf878ba
1 /*
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 * ========================================================================
15 #include "headers.h"
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 *, int *, char **, char **, RemoteType *);
25 RemoteType check_for_header_msg(MAILSTREAM *);
26 char *ptype(RemoteType);
27 char *spechdr(RemoteType);
28 int add_initial_msg(MAILSTREAM *, char *, char *);
29 int append_data(MAILSTREAM *, char *, char *, FILE *);
30 void trim_data(MAILSTREAM *, int);
31 void write_fake_headers(RFC822BUFFER *, char *, char *, char *);
32 char *err_desc(int);
33 int opt_enter(char *, int, char *, int *);
36 int noshow_error = 0;
37 char *ustr = "usage: %s [-s trimSize] [-f] -t Type -l Local_file -r Remote_folder\n";
40 /* look for my_timer_period in pico directory for an explanation */
41 int my_timer_period = ((IDLE_TIMEOUT + 1)*1000);
44 #ifdef _WINDOWS
46 #undef main
48 app_main (int argc, char argv[])
52 #endif /* _WINDOWS */
56 * rpload [-s trimSize] [-f] -t Type -l Local_file -r Remote_folder
58 * Type is one of abook
59 * pinerc
60 * smime
61 * sig (this is mostly obsolete, literal sigs
62 * should be used instead)
63 * -f means force the folder to be written even if it
64 * doesn't look like it is of the right format
66 * Note: We're not worrying about memory leaks.
68 int
69 main(int argc, char *argv[])
71 MAILSTREAM *stream = NULL;
72 FILE *fp;
73 int delete_existing = 0, usage = 0;
74 int force = 0, trimsize = 0;
75 char *local = NULL, *remote = NULL, *special_hdr = NULL;
76 RemoteType rt, type = NotSet;
78 #include "../c-client/linkage.c"
80 if(parse_args(argc, argv, &force, &trimsize, &local, &remote, &type)){
81 fprintf(stderr, ustr, argv[0]);
82 exit(-1);
85 if(!local || !*local){
86 fprintf(stderr, "No local file specified\n");
87 usage++;
90 if(!remote || !*remote){
91 fprintf(stderr, "No remote folder specified\n");
92 usage++;
95 if(type == NotSet){
96 fprintf(stderr, "Type must be set to one of:\n");
97 for(rt = Pinerc; rt != NotSet; rt++)
98 fprintf(stderr, " %s\n", ptype(rt));
100 usage++;
103 if(usage){
104 fprintf(stderr, ustr, argv[0]);
105 exit(-1);
108 if(!IS_REMOTE(remote)){
109 fprintf(stderr,
110 "Remote folder name \"%s\" %s\n", remote,
111 (*remote != '{') ? "must begin with \"{\"" : "not valid");
112 exit(-1);
115 if(IS_REMOTE(local)){
116 fprintf(stderr, "Argument to -l (%s) must be a local filename", local);
117 exit(-1);
120 if(access(local, ACCESS_EXISTS) != 0){
121 fprintf(stderr, "Local file \"%s\" does not exist\n", local);
122 exit(-1);
125 if(access(local, READ_ACCESS) != 0){
126 fprintf(stderr,
127 "Can't read local file \"%s\": %s\n",
128 local, err_desc(errno));
129 exit(-1);
133 * Try opening the local file.
135 if((fp = fopen(local, "r")) == NULL){
136 fprintf(stderr, "Can't open \"%s\": %s\n", local, err_desc(errno));
137 exit(-1);
141 * Try opening the remote folder. If it doesn't exist, create it.
144 /* failure would be normal here, so don't show it */
145 noshow_error = 1;
146 stream = mail_open(NULL, remote, 0L);
147 if(!stream || stream->halfopen){
148 if(stream && stream->halfopen){
149 noshow_error = 0;
150 if(!mail_create(stream, remote))
151 exit(-1);
153 stream = mail_open(stream, remote, 0L);
154 if(!stream || stream->halfopen)
155 exit(-1);
157 else{
158 fprintf(stderr, "Trouble opening remote folder \"%s\"\n", remote);
159 exit(-1);
163 noshow_error = 0;
165 if(stream->rdonly){
166 fprintf(stderr, "Remote folder \"%s\" is not writable\n", remote);
167 exit(-1);
170 if(stream->nmsgs > 0){
172 * There is a first message already. Check to see if it is one of
173 * our special header messages.
175 rt = check_for_header_msg(stream);
176 if(rt == NotSet){
177 if(force)
178 delete_existing++;
179 else{
180 fprintf(stderr, "Folder \"%s\"\ndoes not appear to be an Alpine remote \"%s\" folder.\nUse -f to force.\n", remote, ptype(type));
181 fprintf(stderr, "-f will cause %ld messages to be deleted\n",
182 stream->nmsgs);
183 exit(-1);
186 else if(rt != type){
187 if(force)
188 delete_existing++;
189 else{
190 fprintf(stderr, "Folder \"%s\" is type \"%s\"\nUse -f to force switch.\n", remote, ptype(rt));
191 fprintf(stderr, "-f will cause %ld messages to be deleted\n",
192 stream->nmsgs);
193 exit(-1);
198 if(delete_existing){
199 char sequence[20];
201 mail_ping(stream);
202 snprintf(sequence, sizeof(sequence), "1:%ld", stream->nmsgs);
203 mail_flag(stream, sequence, "\\DELETED", ST_SET);
204 mail_expunge(stream);
205 mail_ping(stream);
208 special_hdr = spechdr(type);
211 * Add the explanatory header message if needed.
213 if(stream->nmsgs == 0){
214 if(add_initial_msg(stream, remote, special_hdr) != 0){
215 mail_close(stream);
216 exit(-1);
221 * Add the actual data in a message.
223 if(append_data(stream, remote, special_hdr, fp) != 0){
224 mail_close(stream);
225 exit(-1);
229 * Trim the size of the remote folder.
231 if(trimsize)
232 trim_data(stream, trimsize);
234 mail_close(stream);
235 exit(0);
239 RemoteType
240 check_for_header_msg(MAILSTREAM *stream)
242 STRINGLIST *sl;
243 int ret = NotSet;
244 char *h, *try;
245 size_t len;
246 char *pinerc, *abook, *sig, *smime;
248 pinerc = spechdr(Pinerc);
249 abook = spechdr(Abook);
250 sig = spechdr(Sig);
251 smime = spechdr(Smime);
253 len = MAX(MAX(strlen(pinerc), strlen(abook)), MAX(strlen(sig), strlen(smime)));
255 sl = mail_newstringlist();
256 sl->text.data = (unsigned char *)fs_get((len+1) * sizeof(unsigned char));
257 try = pinerc;
258 strncpy((char *)sl->text.data, try, len);
259 sl->text.data[len] = '\0';
260 sl->text.size = strlen((char *) sl->text.data);
262 if(stream && (h=mail_fetch_header(stream,1L,NULL,sl,NULL,FT_PEEK))){
264 if(strlen(h) >= sl->text.size && !struncmp(h, try, sl->text.size))
265 ret = Pinerc;
268 if(ret == NotSet){
269 try = abook;
270 strncpy((char *)sl->text.data, try, len);
271 sl->text.data[len] = '\0';
272 sl->text.size = strlen((char *) sl->text.data);
273 if(stream && (h=mail_fetch_header(stream,1L,NULL,sl,NULL,FT_PEEK))){
275 if(strlen(h) >= sl->text.size && !struncmp(h, try, sl->text.size))
276 ret = Abook;
280 if(ret == NotSet){
281 try = sig;
282 strncpy((char *)sl->text.data, try, len);
283 sl->text.data[len] = '\0';
284 sl->text.size = strlen((char *) sl->text.data);
285 if(stream && (h=mail_fetch_header(stream,1L,NULL,sl,NULL,FT_PEEK))){
287 if(strlen(h) >= sl->text.size && !struncmp(h, try, sl->text.size))
288 ret = Sig;
292 if(sl)
293 mail_free_stringlist(&sl);
295 if(pinerc)
296 fs_give((void **)&pinerc);
297 if(abook)
298 fs_give((void **)&abook);
299 if(sig)
300 fs_give((void **)&sig);
301 if(smime)
302 fs_give((void **)&smime);
304 return(ret);
308 char *
309 ptype(RemoteType rtype)
311 char *ret = NULL;
313 switch(rtype){
314 case Pinerc:
315 ret = cpystr("pinerc");
316 break;
317 case Abook:
318 ret = cpystr("abook");
319 break;
320 case Sig:
321 ret = cpystr("sig");
322 break;
323 case Smime:
324 ret = cpystr("smime");
325 break;
326 default:
327 break;
330 return(ret);
334 char *
335 spechdr(RemoteType rtype)
337 char *ret = NULL;
339 switch(rtype){
340 case Pinerc:
341 ret = cpystr(REMOTE_PINERC_SUBTYPE);
342 break;
343 case Abook:
344 ret = cpystr(REMOTE_ABOOK_SUBTYPE);
345 break;
346 case Sig:
347 ret = cpystr(REMOTE_SIG_SUBTYPE);
348 break;
349 case Smime:
350 ret = cpystr(REMOTE_SMIME_SUBTYPE);
351 break;
352 default:
353 break;
356 return(ret);
361 parse_args(int argc, char **argv, int *force, int *trimsize, char **local, char **remote, RemoteType *type)
363 int ac;
364 char **av;
365 int c;
366 char *str;
367 int usage = 0;
368 RemoteType rt;
370 ac = argc;
371 av = argv;
373 /* while more arguments with leading - */
374 Loop: while(--ac > 0 && **++av == '-'){
375 /* while more chars in this argument */
376 while(*++*av){
377 switch(c = **av){
378 case 'h':
379 usage++;
380 break;
381 case 'f':
382 (*force)++;
383 break;
385 case 't': case 'l': /* string args */
386 case 'r':
387 case 's': /* integer args */
388 if(*++*av)
389 str = *av;
390 else if(--ac)
391 str = *++av;
392 else{
393 fprintf(stderr, "missing argument for flag \"%c\"\n", c);
394 ++usage;
395 goto Loop;
398 switch(c){
399 case 'l':
400 if(str)
401 *local = str;
403 break;
404 case 'r':
405 if(str)
406 *remote = str;
408 break;
409 case 't':
410 for(rt = Pinerc; rt != NotSet; rt++){
411 if(!strucmp(str, ptype(rt)))
412 break;
415 *type = rt;
416 break;
417 case 's':
418 if(!isdigit((unsigned char)str[0])){
419 fprintf(stderr,
420 "non-numeric argument for flag \"%c\"\n", c);
421 ++usage;
422 break;
425 *trimsize = atoi(str);
426 if(*trimsize < 1){
427 fprintf(stderr, "trimsize of %d is too small, have to leave at least one copy\n", *trimsize);
428 ++usage;
430 else if(*trimsize > 100){
431 fprintf(stderr,
432 "trimsize of %d is too large, 5 or 10 is sufficient\n",
433 *trimsize);
434 ++usage;
437 break;
440 goto Loop;
442 default:
443 fprintf(stderr, "unknown flag \"%c\"\n", c);
444 ++usage;
445 break;
450 if(ac != 0)
451 usage++;
453 return(usage);
457 long
458 dummy_soutr(void *stream, char *string)
460 return LONGT;
465 * Add an explanatory first message advising user that this is a
466 * special sort of folder.
469 add_initial_msg(MAILSTREAM *stream, char *mailbox, char *special_hdr)
471 STRING msg;
472 char buf[20000];
473 RFC822BUFFER rbuf;
475 rbuf.f = dummy_soutr;
476 rbuf.s = NULL;
477 rbuf.beg = buf;
478 rbuf.cur = buf;
479 rbuf.end = buf+sizeof(buf)-1;
480 write_fake_headers(&rbuf, "Header Message for Remote Data", "plain", special_hdr);
481 *rbuf.cur = '\0';
483 buf[sizeof(buf)-1] = '\0';
485 if(!strucmp(special_hdr, REMOTE_ABOOK_SUBTYPE)){
486 strncat(buf, "This folder contains a single Alpine addressbook.\015\012", sizeof(buf)-strlen(buf)-1);
487 strncat(buf, "This message is just an explanatory message.\015\012", sizeof(buf)-strlen(buf)-1);
488 strncat(buf, "The last message in the folder is the live addressbook data.\015\012", sizeof(buf)-strlen(buf)-1);
489 strncat(buf, "The rest of the messages contain previous revisions of the addressbook data.\015\012", sizeof(buf)-strlen(buf)-1);
490 strncat(buf, "To restore a previous revision just delete and expunge all of the messages\015\012", sizeof(buf)-strlen(buf)-1);
491 strncat(buf, "which come after it.\015\012", sizeof(buf)-strlen(buf)-1);
493 else if(!strucmp(special_hdr, REMOTE_PINERC_SUBTYPE)){
494 strncat(buf, "This folder contains an Alpine config file.\015\012", sizeof(buf)-strlen(buf)-1);
495 strncat(buf, "This message is just an explanatory message.\015\012", sizeof(buf)-strlen(buf)-1);
496 strncat(buf, "The last message in the folder is the live config data.\015\012", sizeof(buf)-strlen(buf)-1);
497 strncat(buf, "The rest of the messages contain previous revisions of the data.\015\012", sizeof(buf)-strlen(buf)-1);
498 strncat(buf, "To restore a previous revision just delete and expunge all of the messages\015\012", sizeof(buf)-strlen(buf)-1);
499 strncat(buf, "which come after it.\015\012", sizeof(buf)-strlen(buf)-1);
501 else if(!strucmp(special_hdr, REMOTE_SMIME_SUBTYPE)){
502 strncat(buf, "This folder contains Alpine S/MIME config information.\015\012", sizeof(buf)-strlen(buf)-1);
503 strncat(buf, "This message is just an explanatory message.\015\012", sizeof(buf)-strlen(buf)-1);
504 strncat(buf, "The last message in the folder is the live data.\015\012", sizeof(buf)-strlen(buf)-1);
505 strncat(buf, "The rest of the messages contain previous revisions of the data.\015\012", sizeof(buf)-strlen(buf)-1);
506 strncat(buf, "To restore a previous revision just delete and expunge all of the messages\015\012", sizeof(buf)-strlen(buf)-1);
507 strncat(buf, "which come after it.\015\012", sizeof(buf)-strlen(buf)-1);
509 else{
510 strncat(buf, "This folder contains remote Alpine data.\015\012", sizeof(buf)-strlen(buf)-1);
511 strncat(buf, "This message is just an explanatory message.\015\012", sizeof(buf)-strlen(buf)-1);
512 strncat(buf, "The last message in the folder is the live data.\015\012", sizeof(buf)-strlen(buf)-1);
513 strncat(buf, "The rest of the messages contain previous revisions of the data.\015\012", sizeof(buf)-strlen(buf)-1);
514 strncat(buf, "To restore a previous revision just delete and expunge all of the messages\015\012", sizeof(buf)-strlen(buf)-1);
515 strncat(buf, "which come after it.\015\012", sizeof(buf)-strlen(buf)-1);
518 INIT(&msg, mail_string, (void *)buf, strlen(buf));
519 if(!mail_append(stream, mailbox, &msg))
520 return(-1);
522 return(0);
527 * Add a message to the folder with the contents of the local data
528 * in it.
531 append_data(MAILSTREAM *stream, char *mailbox, char *special_hdr, FILE *fp)
533 STRING msg;
534 char buf[20000], *sto, *p;
535 struct stat sbuf;
536 long filelen, len;
537 int c, nextc;
538 RFC822BUFFER rbuf;
540 if(fstat(fileno(fp), &sbuf) != 0){
541 fprintf(stderr, "fstat of local file failed\n");
542 return(-1);
545 filelen = (long) sbuf.st_size;
547 rbuf.f = dummy_soutr;
548 rbuf.s = NULL;
549 rbuf.beg = buf;
550 rbuf.cur = buf;
551 rbuf.end = buf+sizeof(buf)-1;
552 write_fake_headers(&rbuf, "Pine Remote Data Container", special_hdr,
553 special_hdr);
554 *rbuf.cur = '\0';
556 buf[sizeof(buf)-1] = '\0';
558 /* very conservative estimate of space needed */
559 len = filelen + filelen + strlen(buf) + 10;
560 sto = fs_get((len+1) * sizeof(char));
562 strncpy(sto, buf, len);
563 sto[len] = '\0';
564 p = sto + strlen(sto);
565 /* Write the contents */
566 while((c = getc(fp)) != EOF){
568 * c-client expects CRLF-terminated lines. These lines
569 * can be either CRLF- or LF-terminated. We have to convert them
570 * when we copy into c-client.
572 if(c == '\r' || c == '\n'){
573 if(c == '\r' && ((nextc = getc(fp)) != '\n') && nextc != EOF)
574 ungetc(nextc, fp);
576 /* write the CRFL */
577 if(p - sto < len)
578 *p++ = '\r';
580 if(p - sto < len)
581 *p++ = '\n';
583 else if(p - sto < len)
584 *p++ = c;
587 fclose(fp);
588 if(p - sto < len)
589 *p = '\0';
591 sto[len] = '\0';
593 INIT(&msg, mail_string, (void *)sto, strlen(sto));
594 if(!mail_append(stream, mailbox, &msg)){
595 fprintf(stderr, "Copy failed\n");
596 return(-1);
599 fs_give((void **)&sto);
601 return(0);
606 * Trim the number of saved copies of the remote data history in case
607 * this is the only way this folder is ever updated. We leave
608 * the first message there because it is supposed to be an explanatory
609 * message, but we don't actually check to see whether or not it is
610 * such a message or not.
612 void
613 trim_data(MAILSTREAM *stream, int trimsize)
615 if(stream->nmsgs > trimsize + 1){
616 char sequence[20];
618 mail_ping(stream);
619 snprintf(sequence, sizeof(sequence), "2:%ld", stream->nmsgs - trimsize);
620 mail_flag(stream, sequence, "\\DELETED", ST_SET);
621 mail_expunge(stream);
626 void
627 write_fake_headers(RFC822BUFFER *where, char *subject, char *subtype, char *special_hdr)
629 ENVELOPE *fake_env;
630 BODY *fake_body;
631 ADDRESS *fake_from;
632 char date[200], vers[10];
634 fake_env = (ENVELOPE *)fs_get(sizeof(ENVELOPE));
635 memset(fake_env, 0, sizeof(ENVELOPE));
636 fake_body = (BODY *)fs_get(sizeof(BODY));
637 memset(fake_body, 0, sizeof(BODY));
638 fake_from = (ADDRESS *)fs_get(sizeof(ADDRESS));
639 memset(fake_from, 0, sizeof(ADDRESS));
640 rfc822_date(date);
642 fake_env->subject = cpystr(subject);
643 fake_env->date = (unsigned char *) cpystr(date);
644 fake_from->personal = cpystr("Pine Remote Data");
645 fake_from->mailbox = cpystr("nobody");
646 fake_from->host = cpystr("nowhere");
647 fake_env->from = fake_from;
648 fake_body->type = REMOTE_DATA_TYPE;
649 fake_body->subtype = cpystr(subtype);
651 snprintf(vers, sizeof(vers), "%d", REMOTE_DATA_VERS_NUM);
653 /* re-use subtype for special header name, too */
654 rfc822_output_header_line(where, special_hdr, 0L, vers);
655 rfc822_output_header(where, fake_env, fake_body, NULL, 0L);
656 mail_free_envelope(&fake_env);
657 mail_free_body(&fake_body);
661 char *
662 err_desc(int err)
664 return((char *) strerror(err));
668 void mm_exists(MAILSTREAM *stream, unsigned long number)
673 void mm_expunged(MAILSTREAM *stream, unsigned long number)
678 void mm_flags(MAILSTREAM *stream, unsigned long number)
683 void mm_list(MAILSTREAM *stream, int delim, char *name, long attrib)
688 void mm_lsub(MAILSTREAM *stream, int delimiter, char *name, long attributes)
693 void mm_notify(MAILSTREAM *stream, char *string, long errflg)
695 mm_log(string, errflg);
699 void mm_log(char *string, long errflg)
701 if(noshow_error)
702 return;
704 switch(errflg){
705 case BYE:
706 case NIL:
707 break;
709 case PARSE:
710 fprintf(stderr, "PARSE: %s\n", string);
711 break;
713 case WARN:
714 fprintf(stderr, "WARN: %s\n", string);
715 break;
717 case ERROR:
718 fprintf(stderr, "ERROR: %s\n", string);
719 break;
721 default:
722 fprintf(stderr, "%s\n", string);
723 break;
727 void mm_login_method(NETMBX *mb, char *user, void *pwd, long trial, char *method)
729 mm_login(mb, user, (char **) pwd, trial);
732 void mm_login(NETMBX *mb, char *user, char **pwd, long trial)
734 char prompt[100], *last, tmp[MAILTMPLEN];
735 int i, j, goal, ugoal, len, rc, flags = 0;
736 #define NETMAXPASSWD 100
738 user[NETMAXUSER-1] = '\0';
740 if(trial == 0L){
741 if(mb->user && *mb->user){
742 strncpy(user, mb->user, NETMAXUSER);
743 user[NETMAXUSER-1] = '\0';
747 if(!*mb->user){
748 /* Dress up long hostnames */
749 snprintf(prompt, sizeof(prompt), "%sHOST: ",
750 (mb->sslflag||mb->tlsflag) ? "+ " : "");
751 len = strlen(prompt);
752 /* leave space for "HOST", "ENTER NAME", and 15 chars for input name */
753 goal = 80 - (len + 20 + MIN(15, 80/5));
754 last = " ENTER LOGIN NAME: ";
755 if(goal < 9){
756 last = " LOGIN: ";
757 if((goal += 13) < 9){
758 last += 1;
759 goal = 0;
763 if(goal){
764 for(i = len, j = 0;
765 i < sizeof(prompt) && (prompt[i] = mb->host[j]); i++, j++)
766 if(i == goal && mb->host[goal+1] && i < sizeof(prompt)){
767 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
768 prompt[sizeof(prompt)-1] = '\0';
769 break;
772 else
773 i = 0;
775 strncpy(&prompt[i], last, sizeof(prompt)-i);
776 prompt[sizeof(prompt)-1] = '\0';
778 while(1) {
779 rc = opt_enter(user, NETMAXUSER, prompt, &flags);
780 if(rc != 4)
781 break;
784 if(rc == 1 || !user[0]) {
785 user[0] = '\0';
788 else
789 strncpy(user, mb->user, NETMAXUSER);
791 user[NETMAXUSER-1] = '\0';
792 // pwd[NETMAXPASSWD-1] = '\0';
794 if(!user[0])
795 return;
798 /* Dress up long host/user names */
799 /* leave space for "HOST", "USER" "ENTER PWD", 12 for user 6 for pwd */
800 snprintf(prompt, sizeof(prompt), "%sHOST: ", (mb->sslflag||mb->tlsflag) ? "+ " : "");
801 len = strlen(prompt);
802 goal = strlen(mb->host);
803 ugoal = strlen(user);
804 if((i = 80 - (len + 8 + 18 + 6)) < 14){
805 goal = 0; /* no host! */
806 if((i = 80 - (6 + 18 + 6)) <= 6){
807 ugoal = 0; /* no user! */
808 if((i = 80 - (18 + 6)) <= 0)
809 i = 0;
811 else{
812 ugoal = i; /* whatever's left */
813 i = 0;
816 else
817 while(goal + ugoal > i)
818 if(goal > ugoal)
819 goal--;
820 else
821 ugoal--;
823 if(goal){
824 snprintf(prompt, sizeof(prompt), "%sHOST: ",
825 (mb->sslflag||mb->tlsflag) ? "+ " : "");
826 for(i = len, j = 0;
827 i < sizeof(prompt) && (prompt[i] = mb->host[j]); i++, j++)
828 if(i == goal && mb->host[goal+1] && i < sizeof(prompt)){
829 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
830 prompt[sizeof(prompt)-1] = '\0';
831 break;
834 else
835 i = 0;
837 if(ugoal){
838 strncpy(&prompt[i], &" USER: "[i ? 0 : 2], sizeof(prompt)-i);
839 prompt[sizeof(prompt)-1] = '\0';
840 for(i += strlen(&prompt[i]), j = 0;
841 i < sizeof(prompt) && (prompt[i] = user[j]); i++, j++)
842 if(j == ugoal && user[ugoal+1] && i < sizeof(prompt)){
843 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
844 prompt[sizeof(prompt)-1] = '\0';
845 break;
849 strncpy(&prompt[i], &" ENTER PASSWORD: "[i ? 0 : 8], sizeof(prompt)-i);
850 prompt[sizeof(prompt)-1] = '\0';
852 tmp[0] = '\0';
853 while(1) {
854 flags = OE_PASSWD;
855 rc = opt_enter(tmp, NETMAXPASSWD, prompt, &flags);
856 if(rc != 4)
857 break;
860 if(tmp[0]) *pwd = cpystr(tmp);
861 if(rc == 1 || !tmp[0]) {
862 user[0] = '\0';
863 return;
868 void mm_critical(MAILSTREAM *stream)
873 void mm_nocritical(MAILSTREAM *stream)
878 long mm_diskerror(MAILSTREAM *stream, long errcode, long serious)
880 return T;
884 void mm_fatal(char *string)
886 fprintf(stderr, "%s\n", string);
890 void mm_searched(MAILSTREAM *stream, unsigned long msgno)
895 void mm_status(MAILSTREAM *stream, char *mailbox, MAILSTATUS *status)
899 void mm_dlog(char *string)
901 fprintf(stderr, "%s\n", string);
906 opt_enter(char *string, int field_len, char *prompt, int *flags)
908 char *pw;
909 int return_v = -10;
911 while(return_v == -10){
913 if(flags && *flags & OE_PASSWD){
914 if((pw = getpass(prompt)) != NULL){
915 if(strlen(pw) < field_len){
916 strncpy(string, pw, field_len);
917 string[field_len-1] = '\0';
918 return_v = 0;
920 else{
921 fputs("Password too long\n", stderr);
922 return_v = -1;
925 else
926 return_v = 1; /* cancel? */
928 else{
929 char *p;
931 fputs(prompt, stdout);
932 if(!fgets(string, field_len, stdin))
933 return_v = 1; /* cancel? */
934 string[field_len-1] = '\0';
935 if((p = strpbrk(string, "\r\n")) != NULL)
936 *p = '\0';
938 return_v = 0;
942 return(return_v);