Add support for tab-completion when selecting by rule
[alpine.git] / alpine / rpload.c
blobdd3e43e6aa63760969da244b27fb96d861edd9e1
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 (argc, argv)
49 int argc;
50 char argv[];
54 #endif /* _WINDOWS */
58 * rpload [-s trimSize] [-f] -t Type -l Local_file -r Remote_folder
60 * Type is one of abook
61 * pinerc
62 * smime
63 * sig (this is mostly obsolete, literal sigs
64 * should be used instead)
65 * -f means force the folder to be written even if it
66 * doesn't look like it is of the right format
68 * Note: We're not worrying about memory leaks.
70 int
71 main(argc, argv)
72 int argc;
73 char *argv[];
75 MAILSTREAM *stream = NULL;
76 FILE *fp;
77 int delete_existing = 0, usage = 0;
78 int force = 0, trimsize = 0;
79 char *local = NULL, *remote = NULL, *special_hdr = NULL;
80 RemoteType rt, type = NotSet;
82 #include "../c-client/linkage.c"
84 if(parse_args(argc, argv, &force, &trimsize, &local, &remote, &type)){
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(type == NotSet){
100 fprintf(stderr, "Type must be set to one of:\n");
101 for(rt = Pinerc; rt != NotSet; rt++)
102 fprintf(stderr, " %s\n", ptype(rt));
104 usage++;
107 if(usage){
108 fprintf(stderr, ustr, argv[0]);
109 exit(-1);
112 if(!IS_REMOTE(remote)){
113 fprintf(stderr,
114 "Remote folder name \"%s\" %s\n", remote,
115 (*remote != '{') ? "must begin with \"{\"" : "not valid");
116 exit(-1);
119 if(IS_REMOTE(local)){
120 fprintf(stderr, "Argument to -l (%s) must be a local filename", local);
121 exit(-1);
124 if(access(local, ACCESS_EXISTS) != 0){
125 fprintf(stderr, "Local file \"%s\" does not exist\n", local);
126 exit(-1);
129 if(access(local, READ_ACCESS) != 0){
130 fprintf(stderr,
131 "Can't read local file \"%s\": %s\n",
132 local, err_desc(errno));
133 exit(-1);
137 * Try opening the local file.
139 if((fp = fopen(local, "r")) == NULL){
140 fprintf(stderr, "Can't open \"%s\": %s\n", local, err_desc(errno));
141 exit(-1);
145 * Try opening the remote folder. If it doesn't exist, create it.
148 /* failure would be normal here, so don't show it */
149 noshow_error = 1;
150 stream = mail_open(NULL, remote, 0L);
151 if(!stream || stream->halfopen){
152 if(stream && stream->halfopen){
153 noshow_error = 0;
154 if(!mail_create(stream, remote))
155 exit(-1);
157 stream = mail_open(stream, remote, 0L);
158 if(!stream || stream->halfopen)
159 exit(-1);
161 else{
162 fprintf(stderr, "Trouble opening remote folder \"%s\"\n", remote);
163 exit(-1);
167 noshow_error = 0;
169 if(stream->rdonly){
170 fprintf(stderr, "Remote folder \"%s\" is not writable\n", remote);
171 exit(-1);
174 if(stream->nmsgs > 0){
176 * There is a first message already. Check to see if it is one of
177 * our special header messages.
179 rt = check_for_header_msg(stream);
180 if(rt == NotSet){
181 if(force)
182 delete_existing++;
183 else{
184 fprintf(stderr, "Folder \"%s\"\ndoes not appear to be an Alpine remote \"%s\" folder.\nUse -f to force.\n", remote, ptype(type));
185 fprintf(stderr, "-f will cause %ld messages to be deleted\n",
186 stream->nmsgs);
187 exit(-1);
190 else if(rt != type){
191 if(force)
192 delete_existing++;
193 else{
194 fprintf(stderr, "Folder \"%s\" is type \"%s\"\nUse -f to force switch.\n", remote, ptype(rt));
195 fprintf(stderr, "-f will cause %ld messages to be deleted\n",
196 stream->nmsgs);
197 exit(-1);
202 if(delete_existing){
203 char sequence[20];
205 mail_ping(stream);
206 snprintf(sequence, sizeof(sequence), "1:%ld", stream->nmsgs);
207 mail_flag(stream, sequence, "\\DELETED", ST_SET);
208 mail_expunge(stream);
209 mail_ping(stream);
212 special_hdr = spechdr(type);
215 * Add the explanatory header message if needed.
217 if(stream->nmsgs == 0){
218 if(add_initial_msg(stream, remote, special_hdr) != 0){
219 mail_close(stream);
220 exit(-1);
225 * Add the actual data in a message.
227 if(append_data(stream, remote, special_hdr, fp) != 0){
228 mail_close(stream);
229 exit(-1);
233 * Trim the size of the remote folder.
235 if(trimsize)
236 trim_data(stream, trimsize);
238 mail_close(stream);
239 exit(0);
243 RemoteType
244 check_for_header_msg(stream)
245 MAILSTREAM *stream;
247 STRINGLIST *sl;
248 int ret = NotSet;
249 char *h, *try;
250 size_t len;
251 char *pinerc, *abook, *sig, *smime;
253 pinerc = spechdr(Pinerc);
254 abook = spechdr(Abook);
255 sig = spechdr(Sig);
256 smime = spechdr(Smime);
258 len = MAX(MAX(strlen(pinerc), strlen(abook)), MAX(strlen(sig), strlen(smime)));
260 sl = mail_newstringlist();
261 sl->text.data = (unsigned char *)fs_get((len+1) * sizeof(unsigned char));
262 try = pinerc;
263 strncpy((char *)sl->text.data, try, len);
264 sl->text.data[len] = '\0';
265 sl->text.size = strlen((char *) sl->text.data);
267 if(stream && (h=mail_fetch_header(stream,1L,NULL,sl,NULL,FT_PEEK))){
269 if(strlen(h) >= sl->text.size && !struncmp(h, try, sl->text.size))
270 ret = Pinerc;
273 if(ret == NotSet){
274 try = abook;
275 strncpy((char *)sl->text.data, try, len);
276 sl->text.data[len] = '\0';
277 sl->text.size = strlen((char *) sl->text.data);
278 if(stream && (h=mail_fetch_header(stream,1L,NULL,sl,NULL,FT_PEEK))){
280 if(strlen(h) >= sl->text.size && !struncmp(h, try, sl->text.size))
281 ret = Abook;
285 if(ret == NotSet){
286 try = sig;
287 strncpy((char *)sl->text.data, try, len);
288 sl->text.data[len] = '\0';
289 sl->text.size = strlen((char *) sl->text.data);
290 if(stream && (h=mail_fetch_header(stream,1L,NULL,sl,NULL,FT_PEEK))){
292 if(strlen(h) >= sl->text.size && !struncmp(h, try, sl->text.size))
293 ret = Sig;
297 if(sl)
298 mail_free_stringlist(&sl);
300 if(pinerc)
301 fs_give((void **)&pinerc);
302 if(abook)
303 fs_give((void **)&abook);
304 if(sig)
305 fs_give((void **)&sig);
306 if(smime)
307 fs_give((void **)&smime);
309 return(ret);
313 char *
314 ptype(rtype)
315 RemoteType rtype;
317 char *ret = NULL;
319 switch(rtype){
320 case Pinerc:
321 ret = cpystr("pinerc");
322 break;
323 case Abook:
324 ret = cpystr("abook");
325 break;
326 case Sig:
327 ret = cpystr("sig");
328 break;
329 case Smime:
330 ret = cpystr("smime");
331 break;
332 default:
333 break;
336 return(ret);
340 char *
341 spechdr(rtype)
342 RemoteType rtype;
344 char *ret = NULL;
346 switch(rtype){
347 case Pinerc:
348 ret = cpystr(REMOTE_PINERC_SUBTYPE);
349 break;
350 case Abook:
351 ret = cpystr(REMOTE_ABOOK_SUBTYPE);
352 break;
353 case Sig:
354 ret = cpystr(REMOTE_SIG_SUBTYPE);
355 break;
356 case Smime:
357 ret = cpystr(REMOTE_SMIME_SUBTYPE);
358 break;
359 default:
360 break;
363 return(ret);
368 parse_args(argc, argv, force, trimsize, local, remote, type)
369 int argc;
370 char **argv;
371 int *force, *trimsize;
372 char **local, **remote;
373 RemoteType *type;
375 int ac;
376 char **av;
377 int c;
378 char *str;
379 int usage = 0;
380 RemoteType rt;
382 ac = argc;
383 av = argv;
385 /* while more arguments with leading - */
386 Loop: while(--ac > 0 && **++av == '-'){
387 /* while more chars in this argument */
388 while(*++*av){
389 switch(c = **av){
390 case 'h':
391 usage++;
392 break;
393 case 'f':
394 (*force)++;
395 break;
397 case 't': case 'l': /* string args */
398 case 'r':
399 case 's': /* integer args */
400 if(*++*av)
401 str = *av;
402 else if(--ac)
403 str = *++av;
404 else{
405 fprintf(stderr, "missing argument for flag \"%c\"\n", c);
406 ++usage;
407 goto Loop;
410 switch(c){
411 case 'l':
412 if(str)
413 *local = str;
415 break;
416 case 'r':
417 if(str)
418 *remote = str;
420 break;
421 case 't':
422 for(rt = Pinerc; rt != NotSet; rt++){
423 if(!strucmp(str, ptype(rt)))
424 break;
427 *type = rt;
428 break;
429 case 's':
430 if(!isdigit((unsigned char)str[0])){
431 fprintf(stderr,
432 "non-numeric argument for flag \"%c\"\n", c);
433 ++usage;
434 break;
437 *trimsize = atoi(str);
438 if(*trimsize < 1){
439 fprintf(stderr, "trimsize of %d is too small, have to leave at least one copy\n", *trimsize);
440 ++usage;
442 else if(*trimsize > 100){
443 fprintf(stderr,
444 "trimsize of %d is too large, 5 or 10 is sufficient\n",
445 *trimsize);
446 ++usage;
449 break;
452 goto Loop;
454 default:
455 fprintf(stderr, "unknown flag \"%c\"\n", c);
456 ++usage;
457 break;
462 if(ac != 0)
463 usage++;
465 return(usage);
469 long
470 dummy_soutr(stream, string)
471 void *stream;
472 char *string;
474 return LONGT;
479 * Add an explanatory first message advising user that this is a
480 * special sort of folder.
483 add_initial_msg(stream, mailbox, special_hdr)
484 MAILSTREAM *stream;
485 char *mailbox;
486 char *special_hdr;
488 STRING msg;
489 char buf[20000];
490 RFC822BUFFER rbuf;
492 rbuf.f = dummy_soutr;
493 rbuf.s = NULL;
494 rbuf.beg = buf;
495 rbuf.cur = buf;
496 rbuf.end = buf+sizeof(buf)-1;
497 write_fake_headers(&rbuf, "Header Message for Remote Data", "plain", special_hdr);
498 *rbuf.cur = '\0';
500 buf[sizeof(buf)-1] = '\0';
502 if(!strucmp(special_hdr, REMOTE_ABOOK_SUBTYPE)){
503 strncat(buf, "This folder contains a single Alpine addressbook.\015\012", sizeof(buf)-strlen(buf)-1);
504 strncat(buf, "This message is just an explanatory message.\015\012", sizeof(buf)-strlen(buf)-1);
505 strncat(buf, "The last message in the folder is the live addressbook data.\015\012", sizeof(buf)-strlen(buf)-1);
506 strncat(buf, "The rest of the messages contain previous revisions of the addressbook data.\015\012", sizeof(buf)-strlen(buf)-1);
507 strncat(buf, "To restore a previous revision just delete and expunge all of the messages\015\012", sizeof(buf)-strlen(buf)-1);
508 strncat(buf, "which come after it.\015\012", sizeof(buf)-strlen(buf)-1);
510 else if(!strucmp(special_hdr, REMOTE_PINERC_SUBTYPE)){
511 strncat(buf, "This folder contains an Alpine config file.\015\012", sizeof(buf)-strlen(buf)-1);
512 strncat(buf, "This message is just an explanatory message.\015\012", sizeof(buf)-strlen(buf)-1);
513 strncat(buf, "The last message in the folder is the live config data.\015\012", sizeof(buf)-strlen(buf)-1);
514 strncat(buf, "The rest of the messages contain previous revisions of the data.\015\012", sizeof(buf)-strlen(buf)-1);
515 strncat(buf, "To restore a previous revision just delete and expunge all of the messages\015\012", sizeof(buf)-strlen(buf)-1);
516 strncat(buf, "which come after it.\015\012", sizeof(buf)-strlen(buf)-1);
518 else if(!strucmp(special_hdr, REMOTE_SMIME_SUBTYPE)){
519 strncat(buf, "This folder contains Alpine S/MIME config information.\015\012", sizeof(buf)-strlen(buf)-1);
520 strncat(buf, "This message is just an explanatory message.\015\012", sizeof(buf)-strlen(buf)-1);
521 strncat(buf, "The last message in the folder is the live data.\015\012", sizeof(buf)-strlen(buf)-1);
522 strncat(buf, "The rest of the messages contain previous revisions of the data.\015\012", sizeof(buf)-strlen(buf)-1);
523 strncat(buf, "To restore a previous revision just delete and expunge all of the messages\015\012", sizeof(buf)-strlen(buf)-1);
524 strncat(buf, "which come after it.\015\012", sizeof(buf)-strlen(buf)-1);
526 else{
527 strncat(buf, "This folder contains remote Alpine data.\015\012", sizeof(buf)-strlen(buf)-1);
528 strncat(buf, "This message is just an explanatory message.\015\012", sizeof(buf)-strlen(buf)-1);
529 strncat(buf, "The last message in the folder is the live data.\015\012", sizeof(buf)-strlen(buf)-1);
530 strncat(buf, "The rest of the messages contain previous revisions of the data.\015\012", sizeof(buf)-strlen(buf)-1);
531 strncat(buf, "To restore a previous revision just delete and expunge all of the messages\015\012", sizeof(buf)-strlen(buf)-1);
532 strncat(buf, "which come after it.\015\012", sizeof(buf)-strlen(buf)-1);
535 INIT(&msg, mail_string, (void *)buf, strlen(buf));
536 if(!mail_append(stream, mailbox, &msg))
537 return(-1);
539 return(0);
544 * Add a message to the folder with the contents of the local data
545 * in it.
548 append_data(stream, mailbox, special_hdr, fp)
549 MAILSTREAM *stream;
550 char *mailbox;
551 char *special_hdr;
552 FILE *fp;
554 STRING msg;
555 char buf[20000], *sto, *p;
556 struct stat sbuf;
557 long filelen, len;
558 int c, nextc;
559 RFC822BUFFER rbuf;
561 if(fstat(fileno(fp), &sbuf) != 0){
562 fprintf(stderr, "fstat of local file failed\n");
563 return(-1);
566 filelen = (long) sbuf.st_size;
568 rbuf.f = dummy_soutr;
569 rbuf.s = NULL;
570 rbuf.beg = buf;
571 rbuf.cur = buf;
572 rbuf.end = buf+sizeof(buf)-1;
573 write_fake_headers(&rbuf, "Pine Remote Data Container", special_hdr,
574 special_hdr);
575 *rbuf.cur = '\0';
577 buf[sizeof(buf)-1] = '\0';
579 /* very conservative estimate of space needed */
580 len = filelen + filelen + strlen(buf) + 10;
581 sto = fs_get((len+1) * sizeof(char));
583 strncpy(sto, buf, len);
584 sto[len] = '\0';
585 p = sto + strlen(sto);
586 /* Write the contents */
587 while((c = getc(fp)) != EOF){
589 * c-client expects CRLF-terminated lines. These lines
590 * can be either CRLF- or LF-terminated. We have to convert them
591 * when we copy into c-client.
593 if(c == '\r' || c == '\n'){
594 if(c == '\r' && ((nextc = getc(fp)) != '\n') && nextc != EOF)
595 ungetc(nextc, fp);
597 /* write the CRFL */
598 if(p - sto < len)
599 *p++ = '\r';
601 if(p - sto < len)
602 *p++ = '\n';
604 else if(p - sto < len)
605 *p++ = c;
608 fclose(fp);
609 if(p - sto < len)
610 *p = '\0';
612 sto[len] = '\0';
614 INIT(&msg, mail_string, (void *)sto, strlen(sto));
615 if(!mail_append(stream, mailbox, &msg)){
616 fprintf(stderr, "Copy failed\n");
617 return(-1);
620 fs_give((void **)&sto);
622 return(0);
627 * Trim the number of saved copies of the remote data history in case
628 * this is the only way this folder is ever updated. We leave
629 * the first message there because it is supposed to be an explanatory
630 * message, but we don't actually check to see whether or not it is
631 * such a message or not.
633 void
634 trim_data(stream, trimsize)
635 MAILSTREAM *stream;
636 int trimsize;
638 if(stream->nmsgs > trimsize + 1){
639 char sequence[20];
641 mail_ping(stream);
642 snprintf(sequence, sizeof(sequence), "2:%ld", stream->nmsgs - trimsize);
643 mail_flag(stream, sequence, "\\DELETED", ST_SET);
644 mail_expunge(stream);
649 void
650 write_fake_headers(where, subject, subtype, special_hdr)
651 RFC822BUFFER *where;
652 char *subject;
653 char *subtype;
654 char *special_hdr;
656 ENVELOPE *fake_env;
657 BODY *fake_body;
658 ADDRESS *fake_from;
659 char date[200], vers[10];
661 fake_env = (ENVELOPE *)fs_get(sizeof(ENVELOPE));
662 memset(fake_env, 0, sizeof(ENVELOPE));
663 fake_body = (BODY *)fs_get(sizeof(BODY));
664 memset(fake_body, 0, sizeof(BODY));
665 fake_from = (ADDRESS *)fs_get(sizeof(ADDRESS));
666 memset(fake_from, 0, sizeof(ADDRESS));
667 rfc822_date(date);
669 fake_env->subject = cpystr(subject);
670 fake_env->date = (unsigned char *) cpystr(date);
671 fake_from->personal = cpystr("Pine Remote Data");
672 fake_from->mailbox = cpystr("nobody");
673 fake_from->host = cpystr("nowhere");
674 fake_env->from = fake_from;
675 fake_body->type = REMOTE_DATA_TYPE;
676 fake_body->subtype = cpystr(subtype);
678 snprintf(vers, sizeof(vers), "%d", REMOTE_DATA_VERS_NUM);
680 /* re-use subtype for special header name, too */
681 rfc822_output_header_line(where, special_hdr, 0L, vers);
682 rfc822_output_header(where, fake_env, fake_body, NULL, 0L);
683 mail_free_envelope(&fake_env);
684 mail_free_body(&fake_body);
688 char *
689 err_desc(err)
690 int err;
692 return((char *) strerror(err));
696 void mm_exists(stream, number)
697 MAILSTREAM *stream;
698 unsigned long number;
703 void mm_expunged(stream, number)
704 MAILSTREAM *stream;
705 unsigned long number;
710 void mm_flags(stream, number)
711 MAILSTREAM *stream;
712 unsigned long number;
717 void mm_list(stream, delim, name, attrib)
718 MAILSTREAM *stream;
719 int delim;
720 char *name;
721 long attrib;
726 void mm_lsub(stream, delimiter, name, attributes)
727 MAILSTREAM *stream;
728 int delimiter;
729 char *name;
730 long attributes;
735 void mm_notify(stream, string, errflg)
736 MAILSTREAM *stream;
737 char *string;
738 long errflg;
740 mm_log(string, errflg);
744 void mm_log(string, errflg)
745 char *string;
746 long errflg;
748 if(noshow_error)
749 return;
751 switch(errflg){
752 case BYE:
753 case NIL:
754 break;
756 case PARSE:
757 fprintf(stderr, "PARSE: %s\n", string);
758 break;
760 case WARN:
761 fprintf(stderr, "WARN: %s\n", string);
762 break;
764 case ERROR:
765 fprintf(stderr, "ERROR: %s\n", string);
766 break;
768 default:
769 fprintf(stderr, "%s\n", string);
770 break;
774 void mm_login_method(mb, user, pwd, trial, method)
775 NETMBX *mb;
776 char *user;
777 void *pwd;
778 long trial;
779 char *method;
781 mm_login(mb, user, (char **) pwd, trial);
784 void mm_login(mb, user, pwd, trial)
785 NETMBX *mb;
786 char *user;
787 char **pwd;
788 long trial;
790 char prompt[100], *last, tmp[MAILTMPLEN];
791 int i, j, goal, ugoal, len, rc, flags = 0;
792 #define NETMAXPASSWD 100
794 user[NETMAXUSER-1] = '\0';
796 if(trial == 0L){
797 if(mb->user && *mb->user){
798 strncpy(user, mb->user, NETMAXUSER);
799 user[NETMAXUSER-1] = '\0';
803 if(!*mb->user){
804 /* Dress up long hostnames */
805 snprintf(prompt, sizeof(prompt), "%sHOST: ",
806 (mb->sslflag||mb->tlsflag) ? "+ " : "");
807 len = strlen(prompt);
808 /* leave space for "HOST", "ENTER NAME", and 15 chars for input name */
809 goal = 80 - (len + 20 + MIN(15, 80/5));
810 last = " ENTER LOGIN NAME: ";
811 if(goal < 9){
812 last = " LOGIN: ";
813 if((goal += 13) < 9){
814 last += 1;
815 goal = 0;
819 if(goal){
820 for(i = len, j = 0;
821 i < sizeof(prompt) && (prompt[i] = mb->host[j]); i++, j++)
822 if(i == goal && mb->host[goal+1] && i < sizeof(prompt)){
823 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
824 prompt[sizeof(prompt)-1] = '\0';
825 break;
828 else
829 i = 0;
831 strncpy(&prompt[i], last, sizeof(prompt)-i);
832 prompt[sizeof(prompt)-1] = '\0';
834 while(1) {
835 rc = opt_enter(user, NETMAXUSER, prompt, &flags);
836 if(rc != 4)
837 break;
840 if(rc == 1 || !user[0]) {
841 user[0] = '\0';
844 else
845 strncpy(user, mb->user, NETMAXUSER);
847 user[NETMAXUSER-1] = '\0';
848 // pwd[NETMAXPASSWD-1] = '\0';
850 if(!user[0])
851 return;
854 /* Dress up long host/user names */
855 /* leave space for "HOST", "USER" "ENTER PWD", 12 for user 6 for pwd */
856 snprintf(prompt, sizeof(prompt), "%sHOST: ", (mb->sslflag||mb->tlsflag) ? "+ " : "");
857 len = strlen(prompt);
858 goal = strlen(mb->host);
859 ugoal = strlen(user);
860 if((i = 80 - (len + 8 + 18 + 6)) < 14){
861 goal = 0; /* no host! */
862 if((i = 80 - (6 + 18 + 6)) <= 6){
863 ugoal = 0; /* no user! */
864 if((i = 80 - (18 + 6)) <= 0)
865 i = 0;
867 else{
868 ugoal = i; /* whatever's left */
869 i = 0;
872 else
873 while(goal + ugoal > i)
874 if(goal > ugoal)
875 goal--;
876 else
877 ugoal--;
879 if(goal){
880 snprintf(prompt, sizeof(prompt), "%sHOST: ",
881 (mb->sslflag||mb->tlsflag) ? "+ " : "");
882 for(i = len, j = 0;
883 i < sizeof(prompt) && (prompt[i] = mb->host[j]); i++, j++)
884 if(i == goal && mb->host[goal+1] && i < sizeof(prompt)){
885 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
886 prompt[sizeof(prompt)-1] = '\0';
887 break;
890 else
891 i = 0;
893 if(ugoal){
894 strncpy(&prompt[i], &" USER: "[i ? 0 : 2], sizeof(prompt)-i);
895 prompt[sizeof(prompt)-1] = '\0';
896 for(i += strlen(&prompt[i]), j = 0;
897 i < sizeof(prompt) && (prompt[i] = user[j]); i++, j++)
898 if(j == ugoal && user[ugoal+1] && i < sizeof(prompt)){
899 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
900 prompt[sizeof(prompt)-1] = '\0';
901 break;
905 strncpy(&prompt[i], &" ENTER PASSWORD: "[i ? 0 : 8], sizeof(prompt)-i);
906 prompt[sizeof(prompt)-1] = '\0';
908 tmp[0] = '\0';
909 while(1) {
910 flags = OE_PASSWD;
911 rc = opt_enter(tmp, NETMAXPASSWD, prompt, &flags);
912 if(rc != 4)
913 break;
916 if(tmp[0]) *pwd = cpystr(tmp);
917 if(rc == 1 || !tmp[0]) {
918 user[0] = '\0';
919 return;
924 void mm_critical(stream)
925 MAILSTREAM *stream;
930 void mm_nocritical(stream)
931 MAILSTREAM *stream;
936 long mm_diskerror(stream, errcode, serious)
937 MAILSTREAM *stream;
938 long errcode;
939 long serious;
941 return T;
945 void mm_fatal(string)
946 char *string;
948 fprintf(stderr, "%s\n", string);
952 void mm_searched(stream, msgno)
953 MAILSTREAM *stream;
954 unsigned long msgno;
959 void mm_status(stream, mailbox, status)
960 MAILSTREAM *stream;
961 char *mailbox;
962 MAILSTATUS *status;
966 void mm_dlog(string)
967 char *string;
969 fprintf(stderr, "%s\n", string);
974 opt_enter(string, field_len, prompt, flags)
975 char *string, *prompt;
976 int field_len;
977 int *flags;
979 char *pw;
980 int return_v = -10;
982 while(return_v == -10){
984 if(flags && *flags & OE_PASSWD){
985 if((pw = getpass(prompt)) != NULL){
986 if(strlen(pw) < field_len){
987 strncpy(string, pw, field_len);
988 string[field_len-1] = '\0';
989 return_v = 0;
991 else{
992 fputs("Password too long\n", stderr);
993 return_v = -1;
996 else
997 return_v = 1; /* cancel? */
999 else{
1000 char *p;
1002 fputs(prompt, stdout);
1003 if(!fgets(string, field_len, stdin))
1004 return_v = 1; /* cancel? */
1005 string[field_len-1] = '\0';
1006 if((p = strpbrk(string, "\r\n")) != NULL)
1007 *p = '\0';
1009 return_v = 0;
1013 return(return_v);