32 |
static int transfer_command(void *, void *, char *); |
static int transfer_command(void *, void *, char *); |
33 |
static void process_command(void *, void *, char *, int); |
static void process_command(void *, void *, char *, int); |
34 |
static void transfer_header(void *, void *, struct list *list); |
static void transfer_header(void *, void *, struct list *list); |
|
static void process_header_line(char *); |
|
35 |
static void transfer_body(void *, void *); |
static void transfer_body(void *, void *); |
|
static void add_remailer_commands(void *); |
|
|
static void transform_body(void *sd_server); |
|
36 |
static void process_data(void *sd_client, void *sd_server); |
static void process_data(void *sd_client, void *sd_server); |
37 |
|
|
38 |
|
|
|
/* Auxiliary list handling functions */ |
|
|
/* These belong to the future list.c */ |
|
|
typedef int (*list_iterator_t)(struct list *list, void *data); |
|
|
|
|
|
void |
|
|
list_iterate(struct list *p, list_iterator_t itr, void *data) |
|
|
{ |
|
|
while (p) { |
|
|
struct list *q = p->next; |
|
|
itr(p, data); |
|
|
p = q; |
|
|
}; |
|
|
} |
|
|
|
|
|
void |
|
|
list_append(struct list **a, struct list *b) |
|
|
{ |
|
|
if (!*a) |
|
|
*a = b; |
|
|
else { |
|
|
struct list *p; |
|
|
|
|
|
for (p = *a; p->next; p = p->next) |
|
|
; |
|
|
p->next = b; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
39 |
/* Collect and send headers */ |
/* Collect and send headers */ |
40 |
|
|
41 |
/* Headers spanning multiple lines are wrapped into a single line, preserving |
/* Headers spanning multiple lines are wrapped into a single line, preserving |
67 |
} |
} |
68 |
|
|
69 |
static void |
static void |
70 |
|
add_header(struct list *list, char *line) |
71 |
|
{ |
72 |
|
ASSOC *asc = header_assoc(line); |
73 |
|
list_append(list, asc); |
74 |
|
if (asc->key && strcasecmp(asc->key, "subject") == 0) { |
75 |
|
char *p = strstr(asc->value, BEGIN_TRIGGER); |
76 |
|
|
77 |
|
if (p) { |
78 |
|
asc = xmalloc(sizeof(*asc)); |
79 |
|
|
80 |
|
*p = 0; |
81 |
|
p += sizeof(BEGIN_TRIGGER) - 1; |
82 |
|
asc->key = strdup(X_ANUBIS_RULE_HEADER); |
83 |
|
asc->value = strdup(p); |
84 |
|
list_append(list, asc); |
85 |
|
} |
86 |
|
} |
87 |
|
} |
88 |
|
|
89 |
|
static void |
90 |
collect_headers(void *sd_client, struct list **listp) |
collect_headers(void *sd_client, struct list **listp) |
91 |
{ |
{ |
|
struct list *tail; |
|
92 |
char buf[LINEBUFFER+1]; |
char buf[LINEBUFFER+1]; |
93 |
|
char *line = NULL; |
94 |
|
|
95 |
*listp = tail = NULL; |
*listp = list_create(); |
96 |
while (recvline(SERVER, sd_client, buf, LINEBUFFER)) { |
while (recvline(SERVER, sd_client, buf, LINEBUFFER)) { |
|
if (strncmp(buf, CRLF, 2) == 0) |
|
|
break; |
|
97 |
remcrlf(buf); |
remcrlf(buf); |
98 |
if (isspace(buf[0])) { |
if (isspace(buf[0])) { |
99 |
if (!tail) |
if (!line) |
100 |
/* Something wrong, assume we've got no |
/* Something wrong, assume we've got no |
101 |
headers */ |
headers */ |
102 |
break; |
break; |
103 |
tail->line = xrealloc(tail->line, |
line = xrealloc(line, |
104 |
strlen(tail->line) + |
strlen(line) + strlen(buf) + 2); |
105 |
strlen(buf) + 2); |
strcat(line, "\n"); |
106 |
strcat(tail->line, "\n"); |
strcat(line, buf); |
|
strcat(tail->line, buf); |
|
107 |
} else { |
} else { |
108 |
if (!(topt & (T_BOUNDARY|T_ENTIRE_BODY)) && tail) |
if (line) { |
109 |
get_boundary(tail->line); |
if (!(topt & (T_BOUNDARY|T_ENTIRE_BODY))) |
110 |
tail = new_element(tail, listp, buf); |
get_boundary(line); |
111 |
|
add_header(*listp, line); |
112 |
|
line = NULL; |
113 |
|
} |
114 |
|
if (buf[0] == 0) |
115 |
|
break; |
116 |
|
line = strdup(buf); |
117 |
} |
} |
118 |
} |
} |
119 |
} |
} |
120 |
|
|
121 |
static void |
static void |
122 |
write_header_line (void *sd_server, char *line) |
write_header_line(void *sd_server, char *line) |
123 |
{ |
{ |
124 |
char *p; |
char *p; |
125 |
|
|
130 |
} while (p = strtok(NULL, "\n")); |
} while (p = strtok(NULL, "\n")); |
131 |
} |
} |
132 |
|
|
133 |
void |
static void |
134 |
send_header (void *sd_server, struct list **plist) |
write_assoc(void *sd_server, ASSOC *entry) |
135 |
{ |
{ |
136 |
struct list *p; |
if (entry->key) { |
137 |
p = *plist; |
if (strcmp(entry->key, X_ANUBIS_RULE_HEADER) == 0) |
138 |
while (p) { |
return; |
139 |
struct list *q = p->next; |
swrite(CLIENT, sd_server, entry->key); |
140 |
write_header_line(sd_server, p->line); |
swrite(CLIENT, sd_server, ":"); |
|
free(p->line); |
|
|
free(p); |
|
|
p = q; |
|
141 |
} |
} |
142 |
*plist = NULL; |
write_header_line(sd_server, entry->value); |
143 |
|
} |
144 |
|
|
145 |
|
void |
146 |
|
send_header(void *sd_server, struct list *list) |
147 |
|
{ |
148 |
|
ASSOC *p; |
149 |
|
|
150 |
|
for (p = list_first(list); p; p = list_next(list)) |
151 |
|
write_assoc(sd_server, p); |
152 |
|
} |
153 |
|
|
154 |
|
void |
155 |
|
send_string_list(void *sd_server, struct list *list) |
156 |
|
{ |
157 |
|
char *p; |
158 |
|
|
159 |
|
for (p = list_first(list); p; p = list_next(list)) |
160 |
|
write_header_line(sd_server, p); |
161 |
} |
} |
162 |
|
|
163 |
|
|
184 |
char buf[LINEBUFFER+1]; |
char buf[LINEBUFFER+1]; |
185 |
struct obstack stk; |
struct obstack stk; |
186 |
int state = 0; |
int state = 0; |
|
struct list *tail = NULL; |
|
187 |
int len; |
int len; |
188 |
|
|
189 |
if (topt & T_BOUNDARY) |
if (topt & T_BOUNDARY) { |
190 |
len = strlen(message.boundary); |
len = strlen(message.boundary); |
191 |
|
message.mime_hdr = list_create(); |
192 |
|
} |
193 |
|
|
194 |
obstack_init (&stk); |
obstack_init (&stk); |
195 |
while (state != ST_DONE |
while (state != ST_DONE |
196 |
&& (nread = recvline(SERVER, sd_client, buf, LINEBUFFER))) { |
&& (nread = recvline(SERVER, sd_client, buf, LINEBUFFER))) { |
210 |
if (buf[0] == 0) |
if (buf[0] == 0) |
211 |
state = ST_BODY; |
state = ST_BODY; |
212 |
else |
else |
213 |
tail = new_element(tail, |
list_append(message.mime_hdr, |
214 |
&message.mime_hdr, |
strdup(buf)); |
|
buf); |
|
215 |
break; |
break; |
216 |
|
|
217 |
case ST_BODY: |
case ST_BODY: |
240 |
if (topt & T_BOUNDARY) { |
if (topt & T_BOUNDARY) { |
241 |
swrite(CLIENT, sd_server, message.boundary); |
swrite(CLIENT, sd_server, message.boundary); |
242 |
swrite(CLIENT, sd_server, CRLF); |
swrite(CLIENT, sd_server, CRLF); |
243 |
send_header(sd_server, &message.mime_hdr); |
send_string_list(sd_server, message.mime_hdr); |
244 |
swrite(CLIENT, sd_server, CRLF); |
swrite(CLIENT, sd_server, CRLF); |
245 |
} |
} |
246 |
|
|
328 |
*********************/ |
*********************/ |
329 |
|
|
330 |
static void |
static void |
331 |
|
save_command(char *line) |
332 |
|
{ |
333 |
|
int i; |
334 |
|
ASSOC *asc = xmalloc(sizeof(*asc)); |
335 |
|
|
336 |
|
for (i = 0; line[i] && isspace(line[i]); i++) |
337 |
|
; |
338 |
|
|
339 |
|
asc->key = xmalloc(i + 1); |
340 |
|
memcpy(asc->key, line, i); |
341 |
|
asc->key[i] = 0; |
342 |
|
for (; line[i] && isspace(line[i]); i++) |
343 |
|
; |
344 |
|
if (line[i]) |
345 |
|
asc->value = strdup(&line[i]); |
346 |
|
else |
347 |
|
asc->value = NULL; |
348 |
|
list_append(message.commands, asc); |
349 |
|
} |
350 |
|
|
351 |
|
static void |
352 |
process_command(void *sd_client, void *sd_server, char *command, int size) |
process_command(void *sd_client, void *sd_server, char *command, int size) |
353 |
{ |
{ |
354 |
char buf[LINEBUFFER+1]; |
char buf[LINEBUFFER+1]; |
355 |
safe_strcpy(buf, command); /* make a back-up */ |
safe_strcpy(buf, command); /* make a back-up */ |
356 |
change_to_lower(buf); |
save_command(buf); |
357 |
|
|
358 |
rcfile_process_cond("RULE", COMMAND, command); |
change_to_lower(buf); |
359 |
|
|
360 |
if (strncmp(buf, "starttls", 8) == 0) { |
if (strncmp(buf, "starttls", 8) == 0) { |
361 |
|
|
594 |
if (strncmp(buf, "quit", 4) == 0) |
if (strncmp(buf, "quit", 4) == 0) |
595 |
return 0; /* The QUIT command */ |
return 0; /* The QUIT command */ |
596 |
else if (strncmp(buf, "rset", 4) == 0) { |
else if (strncmp(buf, "rset", 4) == 0) { |
597 |
|
destroy_assoc_list(&message.commands); |
598 |
|
destroy_assoc_list(&message.header); |
599 |
|
destroy_string_list(&message.mime_hdr); |
600 |
xfree(message.body); |
xfree(message.body); |
601 |
xfree(message.boundary); |
xfree(message.boundary); |
|
destroy_list(&message.addlist); |
|
|
destroy_list(&message.remlist); |
|
|
destroy_list(&message.modlist); |
|
|
mopt = 0; |
|
602 |
topt &= ~T_BOUNDARY; |
topt &= ~T_BOUNDARY; |
603 |
topt &= ~T_ERROR; |
topt &= ~T_ERROR; |
|
if (topt & T_SUPERCLIENT) |
|
|
rcfile_process_section(CF_CLIENT, "ALL", NULL); |
|
604 |
} |
} |
605 |
else if (strncmp(buf, "data", 4) == 0) { |
else if (strncmp(buf, "data", 4) == 0) { |
606 |
process_data(sd_client, sd_server); |
process_data(sd_client, sd_server); |
607 |
xfree(message.body); |
xfree(message.body); |
608 |
xfree(message.boundary); |
xfree(message.boundary); |
|
mopt = 0; |
|
609 |
topt &= ~T_BOUNDARY; |
topt &= ~T_BOUNDARY; |
610 |
topt &= ~T_ERROR; |
topt &= ~T_ERROR; |
|
if (topt & T_SUPERCLIENT) |
|
|
rcfile_process_section(CF_CLIENT, "ALL", NULL); |
|
611 |
} |
} |
612 |
} |
} |
613 |
return 1; /* OK */ |
return 1; /* OK */ |
616 |
void |
void |
617 |
process_data(void *sd_client, void *sd_server) |
process_data(void *sd_client, void *sd_server) |
618 |
{ |
{ |
|
struct list *message_hdr; |
|
619 |
char buf[LINEBUFFER+1]; |
char buf[LINEBUFFER+1]; |
620 |
|
|
621 |
alarm(1800); |
alarm(1800); |
622 |
|
|
623 |
collect_headers(sd_client, &message_hdr); |
collect_headers(sd_client, &message.header); |
624 |
collect_body(sd_client, &message.body); |
collect_body(sd_client, &message.body); |
625 |
|
|
626 |
transfer_header(sd_client, sd_server, message_hdr); |
rcfile_process_section(CF_CLIENT, "RULE", NULL, &message); |
627 |
transform_body(sd_server); |
|
628 |
|
transfer_header(sd_client, sd_server, message.header); |
629 |
transfer_body(sd_client, sd_server); |
transfer_body(sd_client, sd_server); |
630 |
|
|
631 |
recvline(CLIENT, sd_server, buf, LINEBUFFER); |
recvline(CLIENT, sd_server, buf, LINEBUFFER); |
636 |
alarm(0); |
alarm(0); |
637 |
} |
} |
638 |
|
|
|
/***************** |
|
|
MESSAGE HEADER |
|
|
******************/ |
|
|
|
|
|
struct header_data { |
|
|
void *sd_client; |
|
|
void *sd_server; |
|
|
struct list *header; |
|
|
}; |
|
|
|
|
|
struct closure { |
|
|
RC_REGEX *regex; |
|
|
char *modify; |
|
|
struct list *head, *tail; |
|
|
}; |
|
|
|
|
|
int |
|
|
action_remove2(struct list *p, void *data) |
|
|
{ |
|
|
struct closure *clos = data; |
|
|
int rc, stat; |
|
|
char **rv = NULL; |
|
|
|
|
|
stat = anubis_regex_match(clos->regex, p->line, &rc, &rv); |
|
|
free_pptr(rv); |
|
|
if (stat) { |
|
|
free(p->line); |
|
|
free(p); |
|
|
} else { |
|
|
p->next = NULL; |
|
|
if (clos->head == NULL) |
|
|
clos->head = p; |
|
|
if (clos->tail) |
|
|
clos->tail->next = p; |
|
|
clos->tail = p; |
|
|
} |
|
|
return 0; |
|
|
} |
|
|
|
|
|
int |
|
|
action_remove(struct list *p, void *data) |
|
|
{ |
|
|
struct header_data *hp = data; |
|
|
struct closure clos; |
|
|
|
|
|
clos.regex = anubis_regex_compile(p->line, 0); |
|
|
clos.head = clos.tail = NULL; |
|
|
list_iterate(hp->header, action_remove2, &clos); |
|
|
hp->header = clos.head; |
|
|
anubis_regex_free(clos.regex); |
|
|
free(p->line); |
|
|
free(p); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
int |
|
|
action_mod2(struct list *p, void *data) |
|
|
{ |
|
|
struct closure *clos = data; |
|
|
int rc, stat; |
|
|
char **rv = NULL; |
|
|
|
|
|
stat = anubis_regex_match(clos->regex, p->line, &rc, &rv); |
|
|
if (stat) { |
|
|
free(p->line); |
|
|
p->line = substitute(clos->modify, rv); |
|
|
if (!p->line) |
|
|
p->line = strdup(clos->modify); |
|
|
free_pptr(rv); |
|
|
} |
|
|
return 0; |
|
|
} |
|
|
|
|
|
int |
|
|
action_mod(struct list *p, void *data) |
|
|
{ |
|
|
struct header_data *hp = data; |
|
|
struct closure clos; |
|
|
|
|
|
clos.regex = anubis_regex_compile(p->line, 0); |
|
|
clos.head = clos.tail = NULL; |
|
|
clos.modify = p->modify; |
|
|
list_iterate(hp->header, action_mod2, &clos); |
|
|
anubis_regex_free(clos.regex); |
|
|
free(p->line); |
|
|
free(p); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
int |
|
|
action_free(struct list *p, void *data) |
|
|
{ |
|
|
free(p->line); |
|
|
free(p); |
|
|
return 0; |
|
|
} |
|
|
|
|
639 |
static void |
static void |
640 |
transfer_header(void *sd_client, void *sd_server, struct list *header_buf) |
transfer_header(void *sd_client, void *sd_server, struct list *header_buf) |
641 |
{ |
{ |
642 |
struct list *p; |
send_header(sd_server, header_buf); |
|
struct header_data hd; |
|
|
|
|
|
hd.sd_server = sd_server; |
|
|
hd.sd_client = sd_client; |
|
|
hd.header = header_buf; |
|
|
|
|
|
for (p = hd.header; p; p = p->next) |
|
|
process_header_line(p->line); |
|
|
|
|
|
#ifdef WITH_GUILE |
|
|
guile_process_list(&header_buf, &message.body); |
|
|
#endif /* WITH_GUILE */ |
|
|
|
|
|
list_iterate(message.remlist, action_remove, &hd); |
|
|
message.remlist = NULL; |
|
|
|
|
|
list_append(&hd.header, message.addlist); |
|
|
message.addlist = NULL; |
|
|
|
|
|
list_iterate(message.modlist, action_mod, &hd); |
|
|
message.modlist = NULL; |
|
|
|
|
|
#ifdef WITH_GUILE |
|
|
guile_postprocess_list(&hd.header, &message.body); |
|
|
#endif /* WITH_GUILE */ |
|
|
|
|
|
send_header(sd_server, &hd.header); |
|
643 |
swrite(CLIENT, sd_server, CRLF); |
swrite(CLIENT, sd_server, CRLF); |
|
|
|
|
list_iterate(hd.header, action_free, NULL); |
|
644 |
} |
} |
645 |
|
|
|
static void |
|
|
process_header_line(char *header_line) |
|
|
{ |
|
|
char *p = 0; |
|
|
char backup[LINEBUFFER+1]; |
|
|
|
|
|
/* |
|
|
The Trigger. |
|
|
*/ |
|
|
|
|
|
p = strstr(header_line, BEGIN_TRIGGER); |
|
|
if (p) { |
|
|
safe_strcpy(backup, p); |
|
|
*p = '\0'; |
|
|
p = backup; |
|
|
p += sizeof(BEGIN_TRIGGER) - 1; |
|
|
} else |
|
|
p = header_line; |
|
|
|
|
|
rcfile_process_cond("RULE", HEADER, p); |
|
|
return; |
|
|
} |
|
646 |
|
|
647 |
/*************** |
/*************** |
648 |
MESSAGE BODY |
MESSAGE BODY |
649 |
****************/ |
****************/ |
650 |
|
|
|
|
|
|
|
|
651 |
static void |
static void |
652 |
raw_transfer(void *sd_client, void *sd_server) |
raw_transfer(void *sd_client, void *sd_server) |
653 |
{ |
{ |
666 |
{ |
{ |
667 |
if (topt & T_BOUNDARY) { |
if (topt & T_BOUNDARY) { |
668 |
send_body(sd_server); |
send_body(sd_server); |
|
#ifdef HAVE_GPG |
|
|
if ((mopt & M_GPG_ENCRYPT) || (mopt & M_GPG_SIGN)) |
|
|
swrite(CLIENT, sd_server, CRLF); |
|
|
#endif /* HAVE_GPG */ |
|
669 |
|
|
670 |
/* Transfer everything else */ |
/* Transfer everything else */ |
671 |
raw_transfer(sd_client, sd_server); |
raw_transfer(sd_client, sd_server); |
674 |
swrite(CLIENT, sd_server, "."CRLF); |
swrite(CLIENT, sd_server, "."CRLF); |
675 |
} |
} |
676 |
|
|
677 |
|
void |
678 |
static void |
message_add_header(MESSAGE *msg, char *hdr) |
|
add_remailer_commands(void *sd_server) |
|
679 |
{ |
{ |
680 |
char buf[1024]; |
list_append(msg->header, header_assoc(hdr)); |
681 |
|
} |
682 |
|
|
683 |
if (!(mopt & M_RMGPG)) { |
void |
684 |
if (mopt & M_RMRRT) { |
message_remove_headers(MESSAGE *msg, char *arg) |
685 |
sprintf(buf, "::"CRLF"Anon-To: %s"CRLF, rm.rrt); |
{ |
686 |
swrite(CLIENT, sd_server, buf); |
ASSOC *asc; |
687 |
} |
RC_REGEX *regex = anubis_regex_compile(arg, 0); |
688 |
else if (mopt & M_RMPOST) { |
|
689 |
sprintf(buf, "::"CRLF"Anon-Post-To: %s"CRLF, rm.post); |
for (asc = list_first(msg->header); asc; |
690 |
swrite(CLIENT, sd_server, buf); |
asc = list_next(msg->header)) { |
691 |
} |
char **rv; |
692 |
if ((mopt & M_RMLT) || (mopt & M_RMRLT)) { |
int rc; |
693 |
sprintf(buf, "Latent-Time: +%s%s"CRLF, |
char *h = assoc_to_header(asc); |
694 |
rm.latent_time, (mopt & M_RMRLT) ? "r" : ""); |
|
695 |
swrite(CLIENT, sd_server, buf); |
if (anubis_regex_match(regex, h, &rc, &rv)) { |
696 |
} |
list_remove_current(msg->header); |
697 |
swrite(CLIENT, sd_server, CRLF); |
assoc_free(asc); |
698 |
if (mopt & M_RMHEADER) { |
} |
699 |
remcrlf(rm.header); |
free(h); |
700 |
swrite(CLIENT, sd_server, "##"CRLF); |
if (rc) |
701 |
swrite(CLIENT, sd_server, rm.header); |
free_pptr(rv); |
|
swrite(CLIENT, sd_server, CRLF); |
|
|
} |
|
702 |
} |
} |
703 |
#ifdef HAVE_GPG |
anubis_regex_free(regex); |
|
else |
|
|
swrite(CLIENT, sd_server, "::"CRLF"Encrypted: PGP"CRLF CRLF); |
|
|
#endif /* HAVE_GPG */ |
|
|
|
|
|
return; |
|
704 |
} |
} |
705 |
|
|
706 |
static void |
void |
707 |
transform_body(void *sd_server) |
message_modify_headers(MESSAGE *msg, char *arg, char *modify) |
708 |
{ |
{ |
709 |
check_all_files(session.client); |
ASSOC *asc; |
710 |
if (!(topt & T_ERROR) && (mopt & M_EXTBODYPROC)) { |
RC_REGEX *regex = anubis_regex_compile(arg, 0); |
711 |
int rs = 0; |
|
712 |
char *extbuf = 0; |
for (asc = list_first(msg->header); asc; |
713 |
extbuf = external_program(&rs, message.exteditor, message.body, 0, 0); |
asc = list_next(msg->header)) { |
714 |
if (rs != -1 && extbuf) { |
char **rv; |
715 |
xfree(message.body); |
int rc; |
716 |
message.body = extbuf; |
char *h = assoc_to_header(asc); |
717 |
|
|
718 |
|
if (anubis_regex_match(regex, h, &rc, &rv)) { |
719 |
|
free(asc->value); |
720 |
|
asc->value = substitute(modify, rv); |
721 |
|
if (!asc->value) |
722 |
|
asc->value = strdup(modify); |
723 |
} |
} |
724 |
|
free(h); |
725 |
|
free_pptr(rv); |
726 |
} |
} |
727 |
|
anubis_regex_free(regex); |
728 |
|
} |
729 |
|
|
730 |
#ifdef HAVE_GPG |
void |
731 |
if (!(topt & T_ERROR) && ((mopt & M_GPG_ENCRYPT) |
message_external_proc(MESSAGE *msg, char *name) |
732 |
|| (mopt & M_GPG_SIGN) || (mopt & M_RMGPG))) |
{ |
733 |
check_gpg(); |
int rc = 0; |
734 |
#endif /* HAVE_GPG */ |
char *extbuf = 0; |
735 |
|
extbuf = external_program(&rc, name, message.body, 0, 0); |
736 |
if (!(topt & T_ERROR)) { |
if (rc != -1 && extbuf) { |
737 |
if (mopt & M_RM) |
xfree(message.body); |
738 |
add_remailer_commands(sd_server); |
message.body = extbuf; |
739 |
} |
} |
|
topt &= ~T_ERROR; |
|
|
return; |
|
740 |
} |
} |
741 |
|
|
742 |
/* EOF */ |
/* EOF */ |