* clear out some warnings by gcc 9.3.1.
[alpine.git] / alpine / rpload.c
blob7cefe2ab5abc1e49331c86531598453686bb264c
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: rpload.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 *, int *, char **, char **, RemoteType *);
29 RemoteType check_for_header_msg(MAILSTREAM *);
30 char *ptype(RemoteType);
31 char *spechdr(RemoteType);
32 int add_initial_msg(MAILSTREAM *, char *, char *);
33 int append_data(MAILSTREAM *, char *, char *, FILE *);
34 void trim_data(MAILSTREAM *, int);
35 void write_fake_headers(RFC822BUFFER *, char *, char *, char *);
36 char *err_desc(int);
37 int opt_enter(char *, int, char *, int *);
40 int noshow_error = 0;
41 char *ustr = "usage: %s [-s trimSize] [-f] -t Type -l Local_file -r Remote_folder\n";
44 /* look for my_timer_period in pico directory for an explanation */
45 int my_timer_period = ((IDLE_TIMEOUT + 1)*1000);
48 #ifdef _WINDOWS
50 #undef main
52 app_main (argc, argv)
53 int argc;
54 char argv[];
58 #endif /* _WINDOWS */
62 * rpload [-s trimSize] [-f] -t Type -l Local_file -r Remote_folder
64 * Type is one of abook
65 * pinerc
66 * smime
67 * sig (this is mostly obsolete, literal sigs
68 * should be used instead)
69 * -f means force the folder to be written even if it
70 * doesn't look like it is of the right format
72 * Note: We're not worrying about memory leaks.
74 int
75 main(argc, argv)
76 int argc;
77 char *argv[];
79 MAILSTREAM *stream = NULL;
80 FILE *fp;
81 int delete_existing = 0, usage = 0;
82 int force = 0, trimsize = 0;
83 char *local = NULL, *remote = NULL, *special_hdr = NULL;
84 RemoteType rt, type = NotSet;
86 #include "../c-client/linkage.c"
88 if(parse_args(argc, argv, &force, &trimsize, &local, &remote, &type)){
89 fprintf(stderr, ustr, argv[0]);
90 exit(-1);
93 if(!local || !*local){
94 fprintf(stderr, "No local file specified\n");
95 usage++;
98 if(!remote || !*remote){
99 fprintf(stderr, "No remote folder specified\n");
100 usage++;
103 if(type == NotSet){
104 fprintf(stderr, "Type must be set to one of:\n");
105 for(rt = Pinerc; rt != NotSet; rt++)
106 fprintf(stderr, " %s\n", ptype(rt));
108 usage++;
111 if(usage){
112 fprintf(stderr, ustr, argv[0]);
113 exit(-1);
116 if(!IS_REMOTE(remote)){
117 fprintf(stderr,
118 "Remote folder name \"%s\" %s\n", remote,
119 (*remote != '{') ? "must begin with \"{\"" : "not valid");
120 exit(-1);
123 if(IS_REMOTE(local)){
124 fprintf(stderr, "Argument to -l (%s) must be a local filename", local);
125 exit(-1);
128 if(access(local, ACCESS_EXISTS) != 0){
129 fprintf(stderr, "Local file \"%s\" does not exist\n", local);
130 exit(-1);
133 if(access(local, READ_ACCESS) != 0){
134 fprintf(stderr,
135 "Can't read local file \"%s\": %s\n",
136 local, err_desc(errno));
137 exit(-1);
141 * Try opening the local file.
143 if((fp = fopen(local, "r")) == NULL){
144 fprintf(stderr, "Can't open \"%s\": %s\n", local, err_desc(errno));
145 exit(-1);
149 * Try opening the remote folder. If it doesn't exist, create it.
152 /* failure would be normal here, so don't show it */
153 noshow_error = 1;
154 stream = mail_open(NULL, remote, 0L);
155 if(!stream || stream->halfopen){
156 if(stream && stream->halfopen){
157 noshow_error = 0;
158 if(!mail_create(stream, remote))
159 exit(-1);
161 stream = mail_open(stream, remote, 0L);
162 if(!stream || stream->halfopen)
163 exit(-1);
165 else{
166 fprintf(stderr, "Trouble opening remote folder \"%s\"\n", remote);
167 exit(-1);
171 noshow_error = 0;
173 if(stream->rdonly){
174 fprintf(stderr, "Remote folder \"%s\" is not writable\n", remote);
175 exit(-1);
178 if(stream->nmsgs > 0){
180 * There is a first message already. Check to see if it is one of
181 * our special header messages.
183 rt = check_for_header_msg(stream);
184 if(rt == NotSet){
185 if(force)
186 delete_existing++;
187 else{
188 fprintf(stderr, "Folder \"%s\"\ndoes not appear to be an Alpine remote \"%s\" folder.\nUse -f to force.\n", remote, ptype(type));
189 fprintf(stderr, "-f will cause %ld messages to be deleted\n",
190 stream->nmsgs);
191 exit(-1);
194 else if(rt != type){
195 if(force)
196 delete_existing++;
197 else{
198 fprintf(stderr, "Folder \"%s\" is type \"%s\"\nUse -f to force switch.\n", remote, ptype(rt));
199 fprintf(stderr, "-f will cause %ld messages to be deleted\n",
200 stream->nmsgs);
201 exit(-1);
206 if(delete_existing){
207 char sequence[20];
209 mail_ping(stream);
210 snprintf(sequence, sizeof(sequence), "1:%ld", stream->nmsgs);
211 mail_flag(stream, sequence, "\\DELETED", ST_SET);
212 mail_expunge(stream);
213 mail_ping(stream);
216 special_hdr = spechdr(type);
219 * Add the explanatory header message if needed.
221 if(stream->nmsgs == 0){
222 if(add_initial_msg(stream, remote, special_hdr) != 0){
223 mail_close(stream);
224 exit(-1);
229 * Add the actual data in a message.
231 if(append_data(stream, remote, special_hdr, fp) != 0){
232 mail_close(stream);
233 exit(-1);
237 * Trim the size of the remote folder.
239 if(trimsize)
240 trim_data(stream, trimsize);
242 mail_close(stream);
243 exit(0);
247 RemoteType
248 check_for_header_msg(stream)
249 MAILSTREAM *stream;
251 STRINGLIST *sl;
252 int ret = NotSet;
253 char *h, *try;
254 size_t len;
255 char *pinerc, *abook, *sig, *smime;
257 pinerc = spechdr(Pinerc);
258 abook = spechdr(Abook);
259 sig = spechdr(Sig);
260 smime = spechdr(Smime);
262 len = MAX(MAX(strlen(pinerc), strlen(abook)), MAX(strlen(sig), strlen(smime)));
264 sl = mail_newstringlist();
265 sl->text.data = (unsigned char *)fs_get((len+1) * sizeof(unsigned char));
266 try = pinerc;
267 strncpy((char *)sl->text.data, try, len);
268 sl->text.data[len] = '\0';
269 sl->text.size = strlen((char *) sl->text.data);
271 if(stream && (h=mail_fetch_header(stream,1L,NULL,sl,NULL,FT_PEEK))){
273 if(strlen(h) >= sl->text.size && !struncmp(h, try, sl->text.size))
274 ret = Pinerc;
277 if(ret == NotSet){
278 try = abook;
279 strncpy((char *)sl->text.data, try, len);
280 sl->text.data[len] = '\0';
281 sl->text.size = strlen((char *) sl->text.data);
282 if(stream && (h=mail_fetch_header(stream,1L,NULL,sl,NULL,FT_PEEK))){
284 if(strlen(h) >= sl->text.size && !struncmp(h, try, sl->text.size))
285 ret = Abook;
289 if(ret == NotSet){
290 try = sig;
291 strncpy((char *)sl->text.data, try, len);
292 sl->text.data[len] = '\0';
293 sl->text.size = strlen((char *) sl->text.data);
294 if(stream && (h=mail_fetch_header(stream,1L,NULL,sl,NULL,FT_PEEK))){
296 if(strlen(h) >= sl->text.size && !struncmp(h, try, sl->text.size))
297 ret = Sig;
301 if(sl)
302 mail_free_stringlist(&sl);
304 if(pinerc)
305 fs_give((void **)&pinerc);
306 if(abook)
307 fs_give((void **)&abook);
308 if(sig)
309 fs_give((void **)&sig);
310 if(smime)
311 fs_give((void **)&smime);
313 return(ret);
317 char *
318 ptype(rtype)
319 RemoteType rtype;
321 char *ret = NULL;
323 switch(rtype){
324 case Pinerc:
325 ret = cpystr("pinerc");
326 break;
327 case Abook:
328 ret = cpystr("abook");
329 break;
330 case Sig:
331 ret = cpystr("sig");
332 break;
333 case Smime:
334 ret = cpystr("smime");
335 break;
336 default:
337 break;
340 return(ret);
344 char *
345 spechdr(rtype)
346 RemoteType rtype;
348 char *ret = NULL;
350 switch(rtype){
351 case Pinerc:
352 ret = cpystr(REMOTE_PINERC_SUBTYPE);
353 break;
354 case Abook:
355 ret = cpystr(REMOTE_ABOOK_SUBTYPE);
356 break;
357 case Sig:
358 ret = cpystr(REMOTE_SIG_SUBTYPE);
359 break;
360 case Smime:
361 ret = cpystr(REMOTE_SMIME_SUBTYPE);
362 break;
363 default:
364 break;
367 return(ret);
372 parse_args(argc, argv, force, trimsize, local, remote, type)
373 int argc;
374 char **argv;
375 int *force, *trimsize;
376 char **local, **remote;
377 RemoteType *type;
379 int ac;
380 char **av;
381 int c;
382 char *str;
383 int usage = 0;
384 RemoteType rt;
386 ac = argc;
387 av = argv;
389 /* while more arguments with leading - */
390 Loop: while(--ac > 0 && **++av == '-'){
391 /* while more chars in this argument */
392 while(*++*av){
393 switch(c = **av){
394 case 'h':
395 usage++;
396 break;
397 case 'f':
398 (*force)++;
399 break;
401 case 't': case 'l': /* string args */
402 case 'r':
403 case 's': /* integer args */
404 if(*++*av)
405 str = *av;
406 else if(--ac)
407 str = *++av;
408 else{
409 fprintf(stderr, "missing argument for flag \"%c\"\n", c);
410 ++usage;
411 goto Loop;
414 switch(c){
415 case 'l':
416 if(str)
417 *local = str;
419 break;
420 case 'r':
421 if(str)
422 *remote = str;
424 break;
425 case 't':
426 for(rt = Pinerc; rt != NotSet; rt++){
427 if(!strucmp(str, ptype(rt)))
428 break;
431 *type = rt;
432 break;
433 case 's':
434 if(!isdigit((unsigned char)str[0])){
435 fprintf(stderr,
436 "non-numeric argument for flag \"%c\"\n", c);
437 ++usage;
438 break;
441 *trimsize = atoi(str);
442 if(*trimsize < 1){
443 fprintf(stderr, "trimsize of %d is too small, have to leave at least one copy\n", *trimsize);
444 ++usage;
446 else if(*trimsize > 100){
447 fprintf(stderr,
448 "trimsize of %d is too large, 5 or 10 is sufficient\n",
449 *trimsize);
450 ++usage;
453 break;
456 goto Loop;
458 default:
459 fprintf(stderr, "unknown flag \"%c\"\n", c);
460 ++usage;
461 break;
466 if(ac != 0)
467 usage++;
469 return(usage);
473 long
474 dummy_soutr(stream, string)
475 void *stream;
476 char *string;
478 return LONGT;
483 * Add an explanatory first message advising user that this is a
484 * special sort of folder.
487 add_initial_msg(stream, mailbox, special_hdr)
488 MAILSTREAM *stream;
489 char *mailbox;
490 char *special_hdr;
492 STRING msg;
493 char buf[20000];
494 RFC822BUFFER rbuf;
496 rbuf.f = dummy_soutr;
497 rbuf.s = NULL;
498 rbuf.beg = buf;
499 rbuf.cur = buf;
500 rbuf.end = buf+sizeof(buf)-1;
501 write_fake_headers(&rbuf, "Header Message for Remote Data", "plain", special_hdr);
502 *rbuf.cur = '\0';
504 buf[sizeof(buf)-1] = '\0';
506 if(!strucmp(special_hdr, REMOTE_ABOOK_SUBTYPE)){
507 strncat(buf, "This folder contains a single Alpine addressbook.\015\012", sizeof(buf)-strlen(buf)-1);
508 strncat(buf, "This message is just an explanatory message.\015\012", sizeof(buf)-strlen(buf)-1);
509 strncat(buf, "The last message in the folder is the live addressbook data.\015\012", sizeof(buf)-strlen(buf)-1);
510 strncat(buf, "The rest of the messages contain previous revisions of the addressbook data.\015\012", sizeof(buf)-strlen(buf)-1);
511 strncat(buf, "To restore a previous revision just delete and expunge all of the messages\015\012", sizeof(buf)-strlen(buf)-1);
512 strncat(buf, "which come after it.\015\012", sizeof(buf)-strlen(buf)-1);
514 else if(!strucmp(special_hdr, REMOTE_PINERC_SUBTYPE)){
515 strncat(buf, "This folder contains an Alpine config file.\015\012", sizeof(buf)-strlen(buf)-1);
516 strncat(buf, "This message is just an explanatory message.\015\012", sizeof(buf)-strlen(buf)-1);
517 strncat(buf, "The last message in the folder is the live config data.\015\012", sizeof(buf)-strlen(buf)-1);
518 strncat(buf, "The rest of the messages contain previous revisions of the data.\015\012", sizeof(buf)-strlen(buf)-1);
519 strncat(buf, "To restore a previous revision just delete and expunge all of the messages\015\012", sizeof(buf)-strlen(buf)-1);
520 strncat(buf, "which come after it.\015\012", sizeof(buf)-strlen(buf)-1);
522 else if(!strucmp(special_hdr, REMOTE_SMIME_SUBTYPE)){
523 strncat(buf, "This folder contains Alpine S/MIME config information.\015\012", sizeof(buf)-strlen(buf)-1);
524 strncat(buf, "This message is just an explanatory message.\015\012", sizeof(buf)-strlen(buf)-1);
525 strncat(buf, "The last message in the folder is the live data.\015\012", sizeof(buf)-strlen(buf)-1);
526 strncat(buf, "The rest of the messages contain previous revisions of the data.\015\012", sizeof(buf)-strlen(buf)-1);
527 strncat(buf, "To restore a previous revision just delete and expunge all of the messages\015\012", sizeof(buf)-strlen(buf)-1);
528 strncat(buf, "which come after it.\015\012", sizeof(buf)-strlen(buf)-1);
530 else{
531 strncat(buf, "This folder contains remote Alpine data.\015\012", sizeof(buf)-strlen(buf)-1);
532 strncat(buf, "This message is just an explanatory message.\015\012", sizeof(buf)-strlen(buf)-1);
533 strncat(buf, "The last message in the folder is the live data.\015\012", sizeof(buf)-strlen(buf)-1);
534 strncat(buf, "The rest of the messages contain previous revisions of the data.\015\012", sizeof(buf)-strlen(buf)-1);
535 strncat(buf, "To restore a previous revision just delete and expunge all of the messages\015\012", sizeof(buf)-strlen(buf)-1);
536 strncat(buf, "which come after it.\015\012", sizeof(buf)-strlen(buf)-1);
539 INIT(&msg, mail_string, (void *)buf, strlen(buf));
540 if(!mail_append(stream, mailbox, &msg))
541 return(-1);
543 return(0);
548 * Add a message to the folder with the contents of the local data
549 * in it.
552 append_data(stream, mailbox, special_hdr, fp)
553 MAILSTREAM *stream;
554 char *mailbox;
555 char *special_hdr;
556 FILE *fp;
558 STRING msg;
559 char buf[20000], *sto, *p;
560 struct stat sbuf;
561 long filelen, len;
562 int c, nextc;
563 RFC822BUFFER rbuf;
565 if(fstat(fileno(fp), &sbuf) != 0){
566 fprintf(stderr, "fstat of local file failed\n");
567 return(-1);
570 filelen = (long) sbuf.st_size;
572 rbuf.f = dummy_soutr;
573 rbuf.s = NULL;
574 rbuf.beg = buf;
575 rbuf.cur = buf;
576 rbuf.end = buf+sizeof(buf)-1;
577 write_fake_headers(&rbuf, "Pine Remote Data Container", special_hdr,
578 special_hdr);
579 *rbuf.cur = '\0';
581 buf[sizeof(buf)-1] = '\0';
583 /* very conservative estimate of space needed */
584 len = filelen + filelen + strlen(buf) + 10;
585 sto = fs_get((len+1) * sizeof(char));
587 strncpy(sto, buf, len);
588 sto[len] = '\0';
589 p = sto + strlen(sto);
590 /* Write the contents */
591 while((c = getc(fp)) != EOF){
593 * c-client expects CRLF-terminated lines. These lines
594 * can be either CRLF- or LF-terminated. We have to convert them
595 * when we copy into c-client.
597 if(c == '\r' || c == '\n'){
598 if(c == '\r' && ((nextc = getc(fp)) != '\n') && nextc != EOF)
599 ungetc(nextc, fp);
601 /* write the CRFL */
602 if(p - sto < len)
603 *p++ = '\r';
605 if(p - sto < len)
606 *p++ = '\n';
608 else if(p - sto < len)
609 *p++ = c;
612 fclose(fp);
613 if(p - sto < len)
614 *p = '\0';
616 sto[len] = '\0';
618 INIT(&msg, mail_string, (void *)sto, strlen(sto));
619 if(!mail_append(stream, mailbox, &msg)){
620 fprintf(stderr, "Copy failed\n");
621 return(-1);
624 fs_give((void **)&sto);
626 return(0);
631 * Trim the number of saved copies of the remote data history in case
632 * this is the only way this folder is ever updated. We leave
633 * the first message there because it is supposed to be an explanatory
634 * message, but we don't actually check to see whether or not it is
635 * such a message or not.
637 void
638 trim_data(stream, trimsize)
639 MAILSTREAM *stream;
640 int trimsize;
642 if(stream->nmsgs > trimsize + 1){
643 char sequence[20];
645 mail_ping(stream);
646 snprintf(sequence, sizeof(sequence), "2:%ld", stream->nmsgs - trimsize);
647 mail_flag(stream, sequence, "\\DELETED", ST_SET);
648 mail_expunge(stream);
653 void
654 write_fake_headers(where, subject, subtype, special_hdr)
655 RFC822BUFFER *where;
656 char *subject;
657 char *subtype;
658 char *special_hdr;
660 ENVELOPE *fake_env;
661 BODY *fake_body;
662 ADDRESS *fake_from;
663 char date[200], vers[10];
665 fake_env = (ENVELOPE *)fs_get(sizeof(ENVELOPE));
666 memset(fake_env, 0, sizeof(ENVELOPE));
667 fake_body = (BODY *)fs_get(sizeof(BODY));
668 memset(fake_body, 0, sizeof(BODY));
669 fake_from = (ADDRESS *)fs_get(sizeof(ADDRESS));
670 memset(fake_from, 0, sizeof(ADDRESS));
671 rfc822_date(date);
673 fake_env->subject = cpystr(subject);
674 fake_env->date = (unsigned char *) cpystr(date);
675 fake_from->personal = cpystr("Pine Remote Data");
676 fake_from->mailbox = cpystr("nobody");
677 fake_from->host = cpystr("nowhere");
678 fake_env->from = fake_from;
679 fake_body->type = REMOTE_DATA_TYPE;
680 fake_body->subtype = cpystr(subtype);
682 snprintf(vers, sizeof(vers), "%d", REMOTE_DATA_VERS_NUM);
684 /* re-use subtype for special header name, too */
685 rfc822_output_header_line(where, special_hdr, 0L, vers);
686 rfc822_output_header(where, fake_env, fake_body, NULL, 0L);
687 mail_free_envelope(&fake_env);
688 mail_free_body(&fake_body);
692 char *
693 err_desc(err)
694 int err;
696 return((char *) strerror(err));
700 void mm_exists(stream, number)
701 MAILSTREAM *stream;
702 unsigned long number;
707 void mm_expunged(stream, number)
708 MAILSTREAM *stream;
709 unsigned long number;
714 void mm_flags(stream, number)
715 MAILSTREAM *stream;
716 unsigned long number;
721 void mm_list(stream, delim, name, attrib)
722 MAILSTREAM *stream;
723 int delim;
724 char *name;
725 long attrib;
730 void mm_lsub(stream, delimiter, name, attributes)
731 MAILSTREAM *stream;
732 int delimiter;
733 char *name;
734 long attributes;
739 void mm_notify(stream, string, errflg)
740 MAILSTREAM *stream;
741 char *string;
742 long errflg;
744 mm_log(string, errflg);
748 void mm_log(string, errflg)
749 char *string;
750 long errflg;
752 if(noshow_error)
753 return;
755 switch(errflg){
756 case BYE:
757 case NIL:
758 break;
760 case PARSE:
761 fprintf(stderr, "PARSE: %s\n", string);
762 break;
764 case WARN:
765 fprintf(stderr, "WARN: %s\n", string);
766 break;
768 case ERROR:
769 fprintf(stderr, "ERROR: %s\n", string);
770 break;
772 default:
773 fprintf(stderr, "%s\n", string);
774 break;
778 void mm_login_method(mb, user, pwd, trial, method)
779 NETMBX *mb;
780 char *user;
781 void *pwd;
782 long trial;
783 char *method;
785 mm_login(mb, user, (char **) pwd, trial);
788 void mm_login(mb, user, pwd, trial)
789 NETMBX *mb;
790 char *user;
791 char **pwd;
792 long trial;
794 char prompt[100], *last, tmp[MAILTMPLEN];
795 int i, j, goal, ugoal, len, rc, flags = 0;
796 #define NETMAXPASSWD 100
798 user[NETMAXUSER-1] = '\0';
800 if(trial == 0L){
801 if(mb->user && *mb->user){
802 strncpy(user, mb->user, NETMAXUSER);
803 user[NETMAXUSER-1] = '\0';
807 if(!*mb->user){
808 /* Dress up long hostnames */
809 snprintf(prompt, sizeof(prompt), "%sHOST: ",
810 (mb->sslflag||mb->tlsflag) ? "+ " : "");
811 len = strlen(prompt);
812 /* leave space for "HOST", "ENTER NAME", and 15 chars for input name */
813 goal = 80 - (len + 20 + MIN(15, 80/5));
814 last = " ENTER LOGIN NAME: ";
815 if(goal < 9){
816 last = " LOGIN: ";
817 if((goal += 13) < 9){
818 last += 1;
819 goal = 0;
823 if(goal){
824 for(i = len, j = 0;
825 i < sizeof(prompt) && (prompt[i] = mb->host[j]); i++, j++)
826 if(i == goal && mb->host[goal+1] && i < sizeof(prompt)){
827 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
828 prompt[sizeof(prompt)-1] = '\0';
829 break;
832 else
833 i = 0;
835 strncpy(&prompt[i], last, sizeof(prompt)-i);
836 prompt[sizeof(prompt)-1] = '\0';
838 while(1) {
839 rc = opt_enter(user, NETMAXUSER, prompt, &flags);
840 if(rc != 4)
841 break;
844 if(rc == 1 || !user[0]) {
845 user[0] = '\0';
848 else
849 strncpy(user, mb->user, NETMAXUSER);
851 user[NETMAXUSER-1] = '\0';
852 // pwd[NETMAXPASSWD-1] = '\0';
854 if(!user[0])
855 return;
858 /* Dress up long host/user names */
859 /* leave space for "HOST", "USER" "ENTER PWD", 12 for user 6 for pwd */
860 snprintf(prompt, sizeof(prompt), "%sHOST: ", (mb->sslflag||mb->tlsflag) ? "+ " : "");
861 len = strlen(prompt);
862 goal = strlen(mb->host);
863 ugoal = strlen(user);
864 if((i = 80 - (len + 8 + 18 + 6)) < 14){
865 goal = 0; /* no host! */
866 if((i = 80 - (6 + 18 + 6)) <= 6){
867 ugoal = 0; /* no user! */
868 if((i = 80 - (18 + 6)) <= 0)
869 i = 0;
871 else{
872 ugoal = i; /* whatever's left */
873 i = 0;
876 else
877 while(goal + ugoal > i)
878 if(goal > ugoal)
879 goal--;
880 else
881 ugoal--;
883 if(goal){
884 snprintf(prompt, sizeof(prompt), "%sHOST: ",
885 (mb->sslflag||mb->tlsflag) ? "+ " : "");
886 for(i = len, j = 0;
887 i < sizeof(prompt) && (prompt[i] = mb->host[j]); i++, j++)
888 if(i == goal && mb->host[goal+1] && i < sizeof(prompt)){
889 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
890 prompt[sizeof(prompt)-1] = '\0';
891 break;
894 else
895 i = 0;
897 if(ugoal){
898 strncpy(&prompt[i], &" USER: "[i ? 0 : 2], sizeof(prompt)-i);
899 prompt[sizeof(prompt)-1] = '\0';
900 for(i += strlen(&prompt[i]), j = 0;
901 i < sizeof(prompt) && (prompt[i] = user[j]); i++, j++)
902 if(j == ugoal && user[ugoal+1] && i < sizeof(prompt)){
903 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
904 prompt[sizeof(prompt)-1] = '\0';
905 break;
909 strncpy(&prompt[i], &" ENTER PASSWORD: "[i ? 0 : 8], sizeof(prompt)-i);
910 prompt[sizeof(prompt)-1] = '\0';
912 tmp[0] = '\0';
913 while(1) {
914 flags = OE_PASSWD;
915 rc = opt_enter(tmp, NETMAXPASSWD, prompt, &flags);
916 if(rc != 4)
917 break;
920 if(tmp[0]) *pwd = cpystr(tmp);
921 if(rc == 1 || !tmp[0]) {
922 user[0] = '\0';
923 return;
928 void mm_critical(stream)
929 MAILSTREAM *stream;
934 void mm_nocritical(stream)
935 MAILSTREAM *stream;
940 long mm_diskerror(stream, errcode, serious)
941 MAILSTREAM *stream;
942 long errcode;
943 long serious;
945 return T;
949 void mm_fatal(string)
950 char *string;
952 fprintf(stderr, "%s\n", string);
956 void mm_searched(stream, msgno)
957 MAILSTREAM *stream;
958 unsigned long msgno;
963 void mm_status(stream, mailbox, status)
964 MAILSTREAM *stream;
965 char *mailbox;
966 MAILSTATUS *status;
970 void mm_dlog(string)
971 char *string;
973 fprintf(stderr, "%s\n", string);
978 opt_enter(string, field_len, prompt, flags)
979 char *string, *prompt;
980 int field_len;
981 int *flags;
983 char *pw;
984 int return_v = -10;
986 while(return_v == -10){
988 if(flags && *flags & OE_PASSWD){
989 if((pw = getpass(prompt)) != NULL){
990 if(strlen(pw) < field_len){
991 strncpy(string, pw, field_len);
992 string[field_len-1] = '\0';
993 return_v = 0;
995 else{
996 fputs("Password too long\n", stderr);
997 return_v = -1;
1000 else
1001 return_v = 1; /* cancel? */
1003 else{
1004 char *p;
1006 fputs(prompt, stdout);
1007 fgets(string, field_len, stdin);
1008 string[field_len-1] = '\0';
1009 if((p = strpbrk(string, "\r\n")) != NULL)
1010 *p = '\0';
1012 return_v = 0;
1016 return(return_v);