1: <?PHP
2: 3: 4:
5:
6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
18: class Dovecot_LDA
19: {
20: 21: 22: 23: 24:
25: var $_envelopeSender;
26:
27: 28: 29: 30: 31:
32: var $_envelopeTo = array();
33:
34: 35: 36: 37: 38:
39: var $_status;
40:
41: 42: 43: 44: 45:
46: var $_data;
47:
48: 49: 50: 51: 52:
53: var $_deliver_fh;
54:
55: function Dovecot_LDA()
56: {
57: $this->_envelopeTo = false;
58: $this->_status = 220;
59: }
60:
61: 62: 63: 64: 65:
66: function connect()
67: {
68: global $conf;
69:
70: if (!isset($conf['kolab']['filter']['dovecot_deliver'])) {
71: return PEAR::raiseError('Path to the dovecot delivery tool missing!');
72: }
73: return true;
74: }
75:
76: 77: 78: 79: 80:
81: function disconnect()
82: {
83: return true;
84: }
85:
86:
87: 88: 89: 90: 91:
92: function mailFrom($sender)
93: {
94: $this->_envelopeSender = $sender;
95: $this->_status = 250;
96: return true;
97: }
98:
99: 100: 101: 102: 103:
104: function rcptTo($rcpt)
105: {
106: $this->_envelopeTo[] = $rcpt;
107: $this->_status = 250;
108: return true;
109: }
110:
111: 112: 113: 114: 115: 116: 117:
118: function _put($cmd)
119: {
120: if ($cmd == "DATA") {
121: $this->_status = 354;
122: } else {
123: $this->_status = 500;
124: return PEAR::raiseError('Dovecot LDA Backend received an unknown command.');
125: }
126: return true;
127: }
128:
129: 130: 131: 132: 133: 134: 135: 136:
137: function _parseResponse($code)
138: {
139: if ($code) {
140: if ($this->_status == $code) {
141: return true;
142: } else {
143: return PEAR::raiseError(sprintf("Dovecot LDA status is %s though %s was expected!.",
144: $this->_status, $code));
145: }
146: } else {
147: return $this->status;
148: }
149: }
150:
151: 152: 153: 154: 155: 156: 157:
158: function _send($data)
159: {
160: $errors = array();
161: if ($data == ".\r\n" or $data == "\r\n.\r\n") {
162: foreach ($this->_envelopeTo as $recipient) {
163: $result = $this->_start_deliver($recipient);
164: if (is_a($result, 'PEAR_Error')) {
165: $errors[] = $result;
166: continue;
167: }
168:
169: $result = $this->_deliver();
170: if (is_a($result, 'PEAR_Error')) {
171: $errors[] = $result;
172: continue;
173: }
174:
175: $result = $this->_stop_deliver();
176: if (is_a($result, 'PEAR_Error')) {
177: $errors[] = $result;
178: continue;
179: }
180: }
181: if (empty($errors)) {
182: $this->_status = 250;
183: } else {
184: $this->_status = 500;
185: $msg = '';
186: foreach ($errors as $error) {
187: $msg[] = $error->getMessage();
188: }
189: return PEAR::raiseError(sprintf("Dovecot delivery failed: %s",
190: join(', ', $msg)));
191: }
192: } else {
193: $this->_data[] = $data;
194: }
195: return true;
196: }
197:
198:
199: 200: 201: 202: 203: 204: 205:
206: function _start_deliver($recipient)
207: {
208: global $conf;
209:
210: Horde::logMessage(sprintf("Starting Dovecot delivery process with UID %d, GID %d (sender=%s, recipient=%s) ...",
211: getmyuid(), getmygid(),
212: $this->_envelopeSender, $recipient), 'DEBUG');
213:
214: $deliver = $conf['kolab']['filter']['dovecot_deliver'];
215:
216: $this->_deliver_fh = popen($deliver . ' -f "' . $this->_envelopeSender .
217: '" -d "' . $recipient . '"', "w");
218: if ($this->_deliver_fh === false) {
219: return PEAR::raiseError('Failed to connect to the dovecot delivery tool!');
220: }
221: return true;
222: }
223:
224: 225: 226: 227: 228:
229: function _stop_deliver()
230: {
231: Horde::logMessage("Stoping Dovecot delivery process ...", 'DEBUG');
232: $retval = pclose($this->_deliver_fh);
233: Horde::logMessage(sprintf("... return value was %d\n", $retval), 'DEBUG');
234: if ($retval != 0) {
235: return PEAR::raiseError('Dovecot LDA Backend delivery process signaled an error.');
236: }
237: return true;
238: }
239:
240: 241: 242: 243: 244:
245: function _deliver()
246: {
247: foreach ($this->_data as $line) {
248: if (!fwrite($this->_deliver_fh, $line)) {
249: return PEAR::raiseError('Dovecot LDA Backend failed writing to the deliver process.');
250: }
251: }
252: return true;
253: }
254: }
255: