* Minor updates to source to update copyright notices (part 1)
[alpine.git] / alpine / rpload.c
blob8f32b6572bd97d6d4fed387d08a005cf64a401de
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-2016 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;
779 void mm_login(mb, user, pwd, trial)
780 NETMBX *mb;
781 char *user;
782 char *pwd;
783 long trial;
785 char prompt[100], *last;
786 int i, j, goal, ugoal, len, rc, flags = 0;
787 #define NETMAXPASSWD 100
789 user[NETMAXUSER-1] = '\0';
791 if(trial == 0L){
792 if(mb->user && *mb->user){
793 strncpy(user, mb->user, NETMAXUSER);
794 user[NETMAXUSER-1] = '\0';
798 if(!*mb->user){
799 /* Dress up long hostnames */
800 snprintf(prompt, sizeof(prompt), "%sHOST: ",
801 (mb->sslflag||mb->tlsflag) ? "+ " : "");
802 len = strlen(prompt);
803 /* leave space for "HOST", "ENTER NAME", and 15 chars for input name */
804 goal = 80 - (len + 20 + MIN(15, 80/5));
805 last = " ENTER LOGIN NAME: ";
806 if(goal < 9){
807 last = " LOGIN: ";
808 if((goal += 13) < 9){
809 last += 1;
810 goal = 0;
814 if(goal){
815 for(i = len, j = 0;
816 i < sizeof(prompt) && (prompt[i] = mb->host[j]); i++, j++)
817 if(i == goal && mb->host[goal+1] && i < sizeof(prompt)){
818 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
819 prompt[sizeof(prompt)-1] = '\0';
820 break;
823 else
824 i = 0;
826 strncpy(&prompt[i], last, sizeof(prompt)-i);
827 prompt[sizeof(prompt)-1] = '\0';
829 while(1) {
830 rc = opt_enter(user, NETMAXUSER, prompt, &flags);
831 if(rc != 4)
832 break;
835 if(rc == 1 || !user[0]) {
836 user[0] = '\0';
837 pwd[0] = '\0';
840 else
841 strncpy(user, mb->user, NETMAXUSER);
843 user[NETMAXUSER-1] = '\0';
844 pwd[NETMAXPASSWD-1] = '\0';
846 if(!user[0])
847 return;
850 /* Dress up long host/user names */
851 /* leave space for "HOST", "USER" "ENTER PWD", 12 for user 6 for pwd */
852 snprintf(prompt, sizeof(prompt), "%sHOST: ", (mb->sslflag||mb->tlsflag) ? "+ " : "");
853 len = strlen(prompt);
854 goal = strlen(mb->host);
855 ugoal = strlen(user);
856 if((i = 80 - (len + 8 + 18 + 6)) < 14){
857 goal = 0; /* no host! */
858 if((i = 80 - (6 + 18 + 6)) <= 6){
859 ugoal = 0; /* no user! */
860 if((i = 80 - (18 + 6)) <= 0)
861 i = 0;
863 else{
864 ugoal = i; /* whatever's left */
865 i = 0;
868 else
869 while(goal + ugoal > i)
870 if(goal > ugoal)
871 goal--;
872 else
873 ugoal--;
875 if(goal){
876 snprintf(prompt, sizeof(prompt), "%sHOST: ",
877 (mb->sslflag||mb->tlsflag) ? "+ " : "");
878 for(i = len, j = 0;
879 i < sizeof(prompt) && (prompt[i] = mb->host[j]); i++, j++)
880 if(i == goal && mb->host[goal+1] && i < sizeof(prompt)){
881 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
882 prompt[sizeof(prompt)-1] = '\0';
883 break;
886 else
887 i = 0;
889 if(ugoal){
890 strncpy(&prompt[i], &" USER: "[i ? 0 : 2], sizeof(prompt)-i);
891 prompt[sizeof(prompt)-1] = '\0';
892 for(i += strlen(&prompt[i]), j = 0;
893 i < sizeof(prompt) && (prompt[i] = user[j]); i++, j++)
894 if(j == ugoal && user[ugoal+1] && i < sizeof(prompt)){
895 strncpy(&prompt[i-3], "...", sizeof(prompt)-(i-3));
896 prompt[sizeof(prompt)-1] = '\0';
897 break;
901 strncpy(&prompt[i], &" ENTER PASSWORD: "[i ? 0 : 8], sizeof(prompt)-i);
902 prompt[sizeof(prompt)-1] = '\0';
904 *pwd = '\0';
905 while(1) {
906 flags = OE_PASSWD;
907 rc = opt_enter(pwd, NETMAXPASSWD, prompt, &flags);
908 if(rc != 4)
909 break;
912 if(rc == 1 || !pwd[0]) {
913 user[0] = pwd[0] = '\0';
914 return;
919 void mm_critical(stream)
920 MAILSTREAM *stream;
925 void mm_nocritical(stream)
926 MAILSTREAM *stream;
931 long mm_diskerror(stream, errcode, serious)
932 MAILSTREAM *stream;
933 long errcode;
934 long serious;
936 return T;
940 void mm_fatal(string)
941 char *string;
943 fprintf(stderr, "%s\n", string);
947 void mm_searched(stream, msgno)
948 MAILSTREAM *stream;
949 unsigned long msgno;
954 void mm_status(stream, mailbox, status)
955 MAILSTREAM *stream;
956 char *mailbox;
957 MAILSTATUS *status;
961 void mm_dlog(string)
962 char *string;
964 fprintf(stderr, "%s\n", string);
969 opt_enter(string, field_len, prompt, flags)
970 char *string, *prompt;
971 int field_len;
972 int *flags;
974 char *pw;
975 int return_v = -10;
977 while(return_v == -10){
979 if(flags && *flags & OE_PASSWD){
980 if((pw = getpass(prompt)) != NULL){
981 if(strlen(pw) < field_len){
982 strncpy(string, pw, field_len);
983 string[field_len-1] = '\0';
984 return_v = 0;
986 else{
987 fputs("Password too long\n", stderr);
988 return_v = -1;
991 else
992 return_v = 1; /* cancel? */
994 else{
995 char *p;
997 fputs(prompt, stdout);
998 fgets(string, field_len, stdin);
999 string[field_len-1] = '\0';
1000 if((p = strpbrk(string, "\r\n")) != NULL)
1001 *p = '\0';
1003 return_v = 0;
1007 return(return_v);