2 <?php // vim: set binary noeol et sw=4 sts=4:
4 // Incluyo directorio del ejecutable como posible directorio de bibliotecas
5 set_include_path(get_include_path().':'.dirname($argv[0]));
7 require_once 'T/general.php';
12 // cargo extensión IMAP
15 $mconf = $CONF['mail'];
16 $gconf = $CONF['general'];
18 $mailbox = @$mconf['mailbox'];
19 switch (@$mconf['protocol']) {
21 $mailbox = $mconf['server'];
26 $port = @$mconf['port'] ? ":{$mconf['port']}" : '';
27 $options = @$mconf['options'] ? "/{$mconf['options']}" : '';
28 $mailbox = "{{$mconf['server']}$port/{$mconf['protocol']}$options}$mailbox";
31 logsdie("Error: el protocolo {$mconf['protocol']} no está soportado");
34 #$mbox = imap_open($mailbox, @$mconf['user'], @$mconf['pass']);
38 $folders = imap_list($mbox, $mailbox, '*');
40 if ($folders == false) {
43 while (list ($key, $val) = each($folders)) {
50 echo "Headers in INBOX\n";
51 $headers = imap_headers($mbox);
54 while (list ($key, $val) = each ($headers)) {
61 for ($i = 1; $i <= imap_num_msg($mbox); $i++)
63 $header = imap_headerinfo($mbox, $i);
64 echo $header->fromaddress . "\n";
65 #var_dump(imap_headerinfo($mbox, $i, 80, 80));
69 $claves = $gconf['claves'];
71 // Errores tratando de conectar al mail
77 $intervalo = $gconf['intervalo'];
78 // Abro mailbox o chillo.
79 if (!($mbox = @imap_open($mailbox, @$mconf['user'], @$mconf['pass']))) {
80 if ($mbox_errcount * $intervalo > 120) { // 2 horas sin poder conectarse
81 logs('Hace 2 horas que no se puede conectar al servidor ('.imap_last_error().')', ERROR);
84 logs('No se pudo conectar al servidor ('.imap_last_error().')', WARNING);
91 logs('Conectado como '.@$mconf['user']." a $mailbox", DEBUG);
92 if (imap_num_msg($mbox) and $hdr = imap_headerinfo($mbox, 1)) {
93 logs("Nuevo mail '{$hdr->subject}' de {$hdr->fromaddress}");
94 @list($padron, $ej, $ent, $codigo) = validar_cabecera($hdr);
96 logs('Cabecera válida', DEBUG);
97 $intento = new T_Intento($padron, $ej, $ent);
98 if (!($err = $intento->validar_entrega($codigo, $claves))) {
99 logs('Entrega aceptada ('.$intento->to_line().')');
100 if (!($err = preparar_entrega($intento, $mbox, 1, $gconf['data_dir']))) {
101 logs('Intento preparado', DEBUG);
102 $res = $intento->hacer_entrega($hdr->fromaddress);
103 if (PEAR::isError($res)) {
104 logs('Error al hacer entrega (' . $res->getMessage() . ')', ERROR);
105 enviar_respuesta(R_ERR, $hdr->fromaddress, "Error interno al preparar entrega.\n\nSe envió un mensaje al administrador avisando del problema.", $intento);
106 enviar_respuesta(R_ERR, $mconf['admin'], "Error de la DB al preparar entrega:\n" . $res->getMessage(), $intento);
108 logs('Intento encolado para compilar', DEBUG);
109 enviar_respuesta(R_OK, $hdr->fromaddress, null, $intento);
110 guardar_mbox($mbox, 1, $hdr, @$mconf['mbox_bak']);
113 logs("Error al preparar entrega ($err)", ERROR);
114 enviar_respuesta(R_ERR, $hdr->fromaddress, "Error interno al preparar entrega.\n\nSe envió un mensaje al administrador avisando del problema.", $intento);
115 enviar_respuesta(R_ERR, $mconf['admin'], "Error al preparar entrega:\n$err", $intento);
118 logs("Entrega rechazada ($err)", WARNING);
119 enviar_respuesta(R_ERR, $hdr->fromaddress, $err, $intento);
122 logs('Entrega rechazada (subject inválido)', WARNING);
123 enviar_respuesta(R_ERR, $hdr->fromaddress, "Asunto (subject) inválido.\n\n"
124 . "Recuerde que el formato del asunto es estricto:\n"
125 . "[padrón] [ejercicio].[entrega] [código]\n\n"
126 . "Donde [padrón] es su número de padrón, [ejercicio] es el número de\n"
127 . "ejercicio (1 a 4), [entrega] el número de entrega (1 o 2) y [código]\n"
128 . "es el código verificador que le fue asignado por la cátedra.\n"
131 imap_delete($mbox, 1);
132 logs('Mail borrado', DEBUG);
134 logs('Mensajes purgandos', DEBUG);
135 $intervalo = 0; // Que tome el próximo mail enseguida.
137 logs('No hay mail nuevo', DEBUG);
139 logs('Cerrando conexión', DEBUG);
147 $mail = imap_fetchstructure($mbox, 1);
148 var_dump($mail);exit;
149 for ($mail->parts as $id => $part) {
150 if ($part->type == TYPEAPPLICATION) {
153 } while (!validate_header($header));
156 file_put_contents('attach', fetchbody_decoded($mbox, 4, 2))
157 or die("no se puede escribir archivo de salida\n");
162 function enviar_respuesta($tipo, $to, $mensaje = '', $intento = null) {
164 $subject = '[' . $mconf['prefijo'] . '] Entrega ';
165 if ($tipo == R_OK) $estado = 'ACEPTADA';
166 else $estado = 'RECHAZADA';
168 $body .= "Estado: $estado\n";
169 if ($mensaje) $body .= "\n$mensaje\n";
170 if ($intento) $body .= "\n" . $intento->__toString() . "\n";
171 logs("Envío de mail '$subject' a '$to'\n$body\n", DEBUG);
173 From: {$mconf['from']}
174 Reply-To: {$mconf['admin']}
175 Return-Path: {$mconf['admin']}
176 X-Mailer: $NAME $VERSION
179 mail($to, $subject, $body, $headers);
184 * @returns array($padron, $ej, $entrega, $codigo) o false si no es válida.
186 function validar_cabecera($hdr) {
187 // Subject: padron nro_ej nro_entrega clave_alumno
188 if (preg_match('/^\s*(\d{5})\s+([1-4])\.([12])\s+(.*)$/', $hdr->subject, $m)) {
189 return array_slice($m, 1, 5);
194 function preparar_entrega($intento, $mbox, $msgid, $dir) {
195 logs('Acá debería verificar el cuerpo del mensaje', DEBUG);
196 $path = "$dir/" . $intento->path('intentos');
197 $mail = imap_fetchstructure($mbox, $msgid);
198 if (!mkdir_p($path)) return 'No se pudo crear el directorio';
199 foreach ($mail->parts as $id => $part) {
200 $fname = part_filename($part);
202 logs("Escribiendo archivo '$fname' [enc={$part->encoding}]", DEBUG);
203 $body = imap_fetchbody($mbox, $msgid, $id + 1);
204 if (!file_put_contents("$path/$fname", decode_body($body, $part->encoding))) return "Error al guardar el archivo $fname";
206 //if (part_is_source($part) $has_sources = true;
207 //elseif (part_mime_type($part) == 'application/zip') $has_sources = true;
212 function part_is_source($part) {
213 if (part_mime_type($part) == 'application/zip') return true;
214 /* if (part_mime_type($part) == 'application/octet-stream') {
215 $extension = (part_filename($part));
222 function part_filename($part) {
223 if (!@$part->dparameters or !is_array($part->dparameters)) {
226 foreach ($part->dparameters as $param) {
227 if ($param->attribute == 'FILENAME') {
228 return $param->value;
234 function part_mime_type($part) {
235 switch ($part->type) {
237 return 'text/'.strtolower($part->subtype);
239 return 'multipart/'.strtolower($part->subtype);
241 return 'message/'.strtolower($part->subtype);
242 case TYPEAPPLICATION:
243 return 'application/'.strtolower($part->subtype);
245 return 'audio/'.strtolower($part->subtype);
247 return 'image/'.strtolower($part->subtype);
249 return 'video/'.strtolower($part->subtype);
252 return 'other/'.strtolower($part->subtype);
256 function decode_body($body, $encoding) {
258 case ENC7BIT: return fix_eol($body);
259 case ENC8BIT: return fix_eol($body); //imap_8bit($body);
260 case ENCBINARY: return imap_binary($body);
261 case ENCBASE64: return imap_base64($body);
262 case ENCQUOTEDPRINTABLE: return imap_qprint($body);
263 case ENCOTHER: return $body;
265 logs('Encoding no reconocido.', WARNING);
269 function mkdir_p($target) {
270 if (is_dir($target) or empty($target)) return 1;
271 if (file_exists($target) and !is_dir($target)) return 0;
272 if (mkdir_p(substr($target,0,strrpos($target,'/')))) return mkdir($target);
276 function guardar_mbox($mbox, $msgid, $hdr, $mbox_fname) {
278 $fo = @fopen($mbox_fname, 'a');
280 logserr("No se pudo abrir mbox '$mbox_fname'");
283 fputs($fo, sprintf("From %s@%s %s\n", $hdr->from[0]->mailbox, $hdr->from[0]->host, date('D M j H:i:s Y')));
284 fputs($fo, fix_eol(imap_fetchheader($mbox, $msgid, FT_PREFETCHTEXT)));
286 fputs($fo, fix_eol(imap_body($mbox, $msgid)));
292 function fix_eol($str) {
293 return str_replace("\r\n", "\n", $str);