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