]> git.llucax.com Git - software/sercom-old.git/blob - src/sc_fetch
Manda mails notificando si compila bien.
[software/sercom-old.git] / src / sc_fetch
1 #!/usr/bin/php4
2 <?php // vim: set binary noeol et sw=4 sts=4:
3
4 require_once 'T/general.php';
5
6 define('R_ERR', 0);
7 define('R_OK',  1);
8
9 // cargo extensión IMAP
10 T_dl('imap');
11
12 $mconf = $CONF['mail'];
13 $gconf = $CONF['general'];
14
15 $mailbox = @$mconf['mailbox'];
16 switch (@$mconf['protocol'] ? $mconf['protocol'] : 'mbox') {
17     case 'mbox':
18         $mailbox = $mconf['server'];
19         break;
20     case 'pop':
21     case 'imap':
22     case 'nntp':
23         $port    = @$mconf['port'] ? ":{$mconf['port']}" : '';
24         $options = @$mconf['options'] ? "/{$mconf['options']}" : '';
25         $mailbox = "{{$mconf['server']}$port/{$mconf['protocol']}$options}$mailbox";
26         break;
27     default:
28         logsdie("Error: el protocolo {$mconf['protocol']} no está soportado");
29 }
30
31 #$mbox = imap_open($mailbox, @$mconf['user'], @$mconf['pass']);
32
33 /*
34 echo "Mailboxes\n";
35 $folders = imap_list($mbox, $mailbox, '*');
36
37 if ($folders == false) {
38     echo "Call failed\n";
39 } else {
40     while (list ($key, $val) = each($folders)) {
41         echo "$val\n";
42     }
43 }
44 */
45
46 /*
47 echo "Headers in INBOX\n";
48 $headers = imap_headers($mbox);
49
50 if ($headers) {
51     while (list ($key, $val) = each ($headers)) {
52         echo "$val\n";
53     }
54 } else {
55     echo "Call failed\n";
56 }
57
58 for ($i = 1; $i <= imap_num_msg($mbox); $i++)
59 {
60     $header = imap_headerinfo($mbox, $i);
61     echo $header->fromaddress . "\n";
62     #var_dump(imap_headerinfo($mbox, $i, 80, 80));
63 }
64 */
65
66 $claves = $gconf['claves'];
67
68 // Errores tratando de conectar al mail
69 $mbox_errcount = 0;
70
71 // Sin cesar.
72 while (1) {
73     // Reseteo intervalo
74     $intervalo = $gconf['intervalo'];
75     // Abro mailbox o chillo.
76     if (!($mbox = imap_open($mailbox, @$mconf['user'], @$mconf['pass']))) {
77         if ($mbox_errcount * $intervalo > 120) { // 2 horas sin poder conectarse
78             logs('Hace 2 horas que no se puede conectar al servidor ('.imap_last_error().')', ERROR);
79             $mbox_errcount = 0;
80         } else {
81             logs('No se pudo conectar al servidor ('.imap_last_error().')', WARNING);
82         }
83         $mbox_errcount++;
84         sleep($intervalo);
85         continue;
86     }
87     $mbox_errcount = 0;
88     logs('Conectado como '.@$mconf['user']." a $mailbox", DEBUG);
89     if (imap_num_msg($mbox) and $hdr = imap_headerinfo($mbox, 1)) {
90         logs("Nuevo mail '{$hdr->subject}' de {$hdr->fromaddress}");
91         @list($padron, $ej, $ent, $codigo) = validar_cabecera($hdr);
92         if ($padron) {
93             logs('Cabecera válida', DEBUG);
94             $intento = new T_Intento($padron, $ej, $ent);
95             if (!($err = $intento->validar_entrega($codigo, $claves))) {
96                 logs('Entrega aceptada ('.$intento->to_line().')');
97                 if (!($err = preparar_entrega($intento, $mbox, 1, $gconf['data_dir']))) {
98                     logs('Intento preparado', DEBUG);
99                     $res = $intento->hacer_entrega($hdr->fromaddress);
100                     if (PEAR::isError($res)) {
101                         logs('Error al hacer entrega (' . $res->getMessage() . ')', ERROR);
102                         enviar_respuesta(R_ERR, $hdr->fromaddress, "Error interno al preparar entrega.\n\nSe envió un mensaje al administrador avisando del problema.", $intento);
103                         enviar_respuesta(R_ERR, $mconf['admin'], "Error de la DB al preparar entrega:\n" . $res->getMessage(), $intento);
104                     } else {
105                         logs('Intento encolado para compilar', DEBUG);
106                         enviar_respuesta(R_OK, $hdr->fromaddress, null, $intento);
107                         guardar_mbox($mbox, 1, $hdr, @$mconf['mbox_bak']);
108                     }
109                 } else {
110                     logs("Error al preparar entrega ($err)", ERROR);
111                     enviar_respuesta(R_ERR, $hdr->fromaddress, "Error interno al preparar entrega.\n\nSe envió un mensaje al administrador avisando del problema.", $intento);
112                     enviar_respuesta(R_ERR, $mconf['admin'], "Error al preparar entrega:\n$err", $intento);
113                 }
114             } else {
115                 logs("Entrega rechazada ($err)", WARNING);
116                 enviar_respuesta(R_ERR, $hdr->fromaddress, $err, $intento);
117             }
118         } else {
119             logs('Entrega rechazada (subject inválido)', WARNING);
120             enviar_respuesta(R_ERR, $hdr->fromaddress, "Asunto (subject) inválido.\n\n"
121                     . "Recuerde que el formato del asunto es estricto:\n"
122                     . "[padrón] [ejercicio].[entrega] [código]\n\n"
123                     . "Donde [padrón] es su número de padrón, [ejercicio] es el número de\n"
124                     . "ejercicio (1 a 4), [entrega] el número de entrega (1 o 2) y [código]\n"
125                     . "es el código verificador que le fue asignado por la cátedra.\n"
126             );
127         }
128         imap_delete($mbox, 1);
129         logs('Mail borrado', DEBUG);
130         imap_expunge($mbox);
131         logs('Mensajes purgandos', DEBUG);
132         $intervalo = 0; // Que tome el próximo mail enseguida.
133     } else {
134         logs('No hay mail nuevo', DEBUG);
135     }
136     logs('Cerrando conexión', DEBUG);
137     imap_close($mbox);
138     sleep($intervalo);
139 }
140
141
142 /*
143 do {
144     $mail = imap_fetchstructure($mbox, 1);
145     var_dump($mail);exit;
146     for ($mail->parts as $id => $part) {
147         if ($part->type == TYPEAPPLICATION) {
148         }
149     }
150 } while (!validate_header($header));
151
152
153 file_put_contents('attach', fetchbody_decoded($mbox, 4, 2))
154     or die("no se puede escribir archivo de salida\n");
155
156 imap_close($mbox);
157 */
158
159 function enviar_respuesta($tipo, $to, $mensaje = '', $intento = null) {
160     global $mconf;
161     $subject = $mconf['prefijo'] . 'Entrega ';
162     if ($tipo == R_OK) $estado = 'ACEPTADA';
163     else               $estado = 'RECHAZADA';
164     $subject .= $estado;
165     $body .= "Estado: $estado\n";
166     if ($mensaje) $body .= "\n$mensaje\n";
167     if ($intento) $body .= "\n" . $intento->__toString() . "\n";
168     logs("Envío de mail '$subject' a '$to'\n$body\n", DEBUG);
169     $headers = <<<EOT
170 From: {$mconf['from']}
171 Reply-To: {$mconf['admin']}
172 Return-Path: {$mconf['admin']}
173 X-Mailer: $NAME $VERSION
174 X-Priority: 5
175 EOT;
176     mail($to, $subject, $body, $headers);
177     return true;
178 }
179
180 /**
181  * @returns array($padron, $ej, $entrega, $codigo) o false si no es válida.
182  */
183 function validar_cabecera($hdr) {
184     // Subject: padron nro_ej nro_entrega clave_alumno
185     if (preg_match('/^\s*(\d{5})\s+([1-4])\.([12])\s+(.*)$/', $hdr->subject, $m)) {
186         return array_slice($m, 1, 5);
187     }
188     return false;
189 }
190
191 function preparar_entrega($intento, $mbox, $msgid, $dir) {
192     logs('Acá debería verificar el cuerpo del mensaje', DEBUG);
193     $mail = imap_fetchstructure($mbox, $msgid);
194     foreach ($mail->parts as $id => $part) {
195         $fname = part_filename($part);
196         if ($fname) {
197             logs("Escribiendo archivo '$fname' [enc={$part->encoding}]", DEBUG);
198             $body = imap_fetchbody($mbox, $msgid, $id + 1);
199             $path = "$dir/" . $intento->path('intentos');
200             if (!mkdir_p($path)) return 'No se pudo crear el directorio';
201             if (!file_put_contents("$path/$fname", decode_body($body, $part->encoding))) return "Error al guardar el archivo $fname";
202         }
203         //if (part_is_source($part) $has_sources = true;
204         //elseif (part_mime_type($part) == 'application/zip') $has_sources = true;
205     }
206     return '';
207 }
208
209 function part_is_source($part) {
210     if (part_mime_type($part) == 'application/zip') return true;
211 /*    if (part_mime_type($part) == 'application/octet-stream') {
212         $extension = (part_filename($part));
213         if (,  {
214         }
215     } */
216     return false;
217 }
218
219 function part_filename($part) {
220     if (!@$part->dparameters or !is_array($part->dparameters)) {
221         return '';
222     }
223     foreach ($part->dparameters as $param) {
224         if ($param->attribute == 'FILENAME') {
225             return $param->value;
226         }
227     }
228     return '';
229 }
230
231 function part_mime_type($part) {
232     switch ($part->type) {
233         case TYPETEXT:
234             return 'text/'.strtolower($part->subtype);
235         case TYPEMULTIPART:
236             return 'multipart/'.strtolower($part->subtype);
237         case TYPEMESSAGE:
238             return 'message/'.strtolower($part->subtype);
239         case TYPEAPPLICATION:
240             return 'application/'.strtolower($part->subtype);
241         case TYPEAUDIO:
242             return 'audio/'.strtolower($part->subtype);
243         case TYPEIMAGE:
244             return 'image/'.strtolower($part->subtype);
245         case TYPEVIDEO:
246             return 'video/'.strtolower($part->subtype);
247         case TYPEOTHER:
248         default:
249             return 'other/'.strtolower($part->subtype);
250     }
251 }
252
253 function decode_body($body, $encoding) {
254     switch ($encoding) {
255         case ENC7BIT:            return fix_eol($body);
256         case ENC8BIT:            return fix_eol($body); //imap_8bit($body);
257         case ENCBINARY:          return imap_binary($body);
258         case ENCBASE64:          return imap_base64($body);
259         case ENCQUOTEDPRINTABLE: return imap_qprint($body);
260         case ENCOTHER:           return $body;
261     }
262     logs('Encoding no reconocido.', WARNING);
263     return $body;
264 }
265
266 function mkdir_p($target) {
267     if (is_dir($target) or empty($target))               return 1;
268     if (file_exists($target) and !is_dir($target))       return 0;
269     if (mkdir_p(substr($target,0,strrpos($target,'/')))) return mkdir($target);
270     return 0;
271 }
272
273 function guardar_mbox($mbox, $msgid, $hdr, $mbox_fname) {
274     if ($mbox_fname) {
275         $fo = @fopen($mbox_fname, 'a');
276         if (!$fo) {
277             logserr("No se pudo abrir mbox '$mbox_fname'");
278             return false;
279         }
280         fputs($fo, sprintf("From %s@%s %s\n", $hdr->from[0]->mailbox, $hdr->from[0]->host, date('D M j H:i:s Y')));
281         fputs($fo, fix_eol(imap_fetchheader($mbox, $msgid, FT_PREFETCHTEXT)));
282         fputs("\n");
283         fputs($fo, fix_eol(imap_body($mbox, $msgid)));
284         fclose($fo);
285     }
286     return true;
287 }
288
289 function fix_eol($str) {
290     return str_replace("\r\n", "\n", $str);
291 }
292
293 ?>