Annotation of parser3/src/classes/mail.C, revision 1.3
1.1 paf 1: /** @file
2: Parser: @b mail parser class.
3:
4: Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
5:
6: Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
7:
1.3 ! paf 8: $Id: mail.C,v 1.2 2001/04/07 11:55:30 paf Exp $
1.1 paf 9: */
10:
11: #include "pa_config_includes.h"
12:
13: #include "_mail.h"
14: #include "pa_common.h"
15: #include "pa_request.h"
16:
17: // global var
18:
19: VStateless_class *mail_class;
20:
1.2 paf 21: // consts
22:
1.1 paf 23: // methods
24:
25: struct Mail_info {
26: String *attribute_to_exclude;
27: String *header;
1.2 paf 28: const String **from, **to;
1.1 paf 29: };
30:
31: static void add_header_attribute(const Hash::Key& aattribute, Hash::Val *ameaning,
32: void *info) {
33:
34: Value& lmeaning=*static_cast<Value *>(ameaning);
35: Mail_info& mi=*static_cast<Mail_info *>(info);
1.2 paf 36:
37: // exclude one attribute [body]
1.1 paf 38: if(aattribute==*mi.attribute_to_exclude)
39: return;
40:
1.2 paf 41: // fetch from & to from header for SMTP
42: if(mi.from && aattribute=="from")
43: *mi.from=&lmeaning.as_string();
44: if(mi.to && aattribute=="to")
45: *mi.to=&lmeaning.as_string();
46:
47: // append header line
48: *mi.header+=aattribute;
49: *mi.header+=":";
50: *mi.header+=attributed_meaning_to_string(lmeaning, String::UL_MAIL_HEADER);
51: *mi.header+="\n";
52: }
53: struct Seq_item {
54: const String *part_number;
55: Value *part_value;
56: };
57: static void add_part(const Hash::Key& part_number, Hash::Val *part_value,
58: void *info) {
59: Seq_item **seq_ref=static_cast<Seq_item **>(info);
60: (**seq_ref).part_number=&part_number;
61: (**seq_ref).part_value=static_cast<Value *>(part_value);
62: (*seq_ref)++;
63: }
64: static double key_of_part(const void *item) {
65: const char *cstr=static_cast<const Seq_item *>(item)->part_number->cstr();
66: char *error_pos;
67: return strtod(cstr, &error_pos);
68: }
69: static int sort_cmp_string_double_value(const void *a, const void *b) {
70: double va=key_of_part(a);
71: double vb=key_of_part(b);
72: if(va<vb)
73: return -1;
74: else if(va>vb)
75: return +1;
76: else
77: return 0;
1.1 paf 78: }
1.2 paf 79: static const String& letter_hash_to_string(Request& r, const String& method_name,
80: Hash& letter_hash, int level,
81: const String **from, const String **to) {
82: Pool& pool=r.pool();
83:
84: // prepare header: 'hash' without "body"
85: String& result=*new(pool) String(pool);
86: Mail_info mail_info={
87: /*excluding*/ body_name,
88: &result,
89: from, to
90: };
91: letter_hash.for_each(add_header_attribute, &mail_info);
92:
93: if(Value *body_element=static_cast<Value *>(letter_hash.get(*body_name))) {
94: if(Hash *body_hash=body_element->get_hash()) {
95: char *boundary=(char *)pool.malloc(MAX_NUMBER);
1.3 ! paf 96: snprintf(boundary, MAX_NUMBER-6/*level_*/, "level_%d", level);
1.2 paf 97: // multi-part
1.3 ! paf 98: ((result+=
! 99: "content-type: multipart/mixed;\n"
! 100: " boundary=\"----=")+=boundary)+="\"\n"
1.2 paf 101: "\n"
102: "This is a multi-part message in MIME format.";
103:
1.3 ! paf 104: // body parts..
! 105: // ..collect
1.2 paf 106: Seq_item *seq=(Seq_item *)malloc(sizeof(Seq_item)*body_hash->size());
107: Seq_item *seq_ref=seq; body_hash->for_each(add_part, &seq_ref);
1.3 ! paf 108: // ..sort
1.2 paf 109: _qsort(seq, body_hash->size(), sizeof(Seq_item),
110: sort_cmp_string_double_value);
1.3 ! paf 111: // ..insert in 'seq' order
1.2 paf 112: for(int i=0; i<body_hash->size(); i++) {
113: // intermediate boundary
1.3 ! paf 114: ((result+="\n------=")+=boundary)+="\n";
1.2 paf 115:
116: if(Hash *part_hash=seq[i].part_value->get_hash())
117: result+=letter_hash_to_string(r, method_name, *part_hash,
118: level+1, 0, 0);
119: else
120: PTHROW(0, 0,
121: seq[i].part_number,
122: "part is not hash");
123: }
124:
125: // finish boundary
1.3 ! paf 126: ((result+="\n------=")+=boundary)+="--\n";
1.2 paf 127: } else {
128: result+="\n"; // header|body separator
129: result+=body_element->as_string();
130: }
131: } else
132: PTHROW(0, 0,
133: &method_name,
134: "has no $body");
135:
136: return result;
137: }
138:
1.1 paf 139: static void _send(Request& r, const String& method_name, Array *params) {
140: Pool& pool=r.pool();
141:
142: Value& vhash=*static_cast<Value *>(params->get(0));
143: // forcing [this body type]
144: r.fail_if_junction_(true, vhash, method_name, "message must not be code");
145:
146: Hash *hash=vhash.get_hash();
147: if(!hash)
148: PTHROW(0, 0,
149: &method_name,
150: "message must be hash");
151:
1.2 paf 152: const String *from, *to;
153: const String& string=letter_hash_to_string(r, method_name, *hash, 0, &from, &to);
1.1 paf 154:
1.2 paf 155: r.write_assign_lang(*new(pool) VString(string));
1.1 paf 156: }
157:
158: // initialize
159: void initialize_mail_class(Pool& pool, VStateless_class& vclass) {
160: // ^mail:send{hash}
161: vclass.add_native_method("send", Method::CT_STATIC, _send, 1, 1);
162: }
E-mail: