Changeset 4898 for contrib/z-push
- Timestamp:
- 08/03/11 12:00:08 (13 years ago)
- Location:
- contrib/z-push
- Files:
-
- 19 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
contrib/z-push/backend/BackendCalendarExpresso.php
r4219 r4898 7 7 * Created : 06.12.2010 - emerson-faria.nobre@serpro.gov.br 8 8 * 9 * ï¿œ Zarafa Deutschland GmbH, www.zarafaserver.de9 * ᅵ Zarafa Deutschland GmbH, www.zarafaserver.de 10 10 * This file is distributed under GPL v2. 11 11 * Consult LICENSE file for details … … 65 65 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 66 66 while ($row = pg_fetch_row($result)) { 67 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageList-> L êitem do BD (cal_id: '.$row[0].', title: '.$row[4].', last_update: '.date("d/m/Y G:i:s",substr($row[1], 0, strlen($row[1])-3)).', last_update_timestamp: '.$row[1].', datetime: '.date("d/m/Y G:i:s",$row[2]).', datetime_timestamp: '.$row[2].', cal_type: '.$row[3].')');67 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageList-> Lê item do BD (cal_id: '.$row[0].', title: '.$row[4].', last_update: '.date("d/m/Y G:i:s",substr($row[1], 0, strlen($row[1])-3)).', last_update_timestamp: '.$row[1].', datetime: '.date("d/m/Y G:i:s",$row[2]).', datetime_timestamp: '.$row[2].', cal_type: '.$row[3].')'); 68 68 $result_recur = pg_query($this->db,"select recur_enddate from phpgw_cal_repeats where cal_id = " . $row[0] . ";"); 69 69 if ($result_recur == FALSE) throw new Exception(pg_last_error($this->db)); 70 70 if ($row[3] == 'M') { 71 71 if ($recur_enddate = pg_fetch_result($result_recur, 0, 0)) { 72 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageList-> Evento '.$row[0].' érecorrente: recur_enddate : '.date("d/m/Y G:i:s",$recur_enddate).', recur_enddate_timestamp: '.$recur_enddate);72 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageList-> Evento '.$row[0].' é recorrente: recur_enddate : '.date("d/m/Y G:i:s",$recur_enddate).', recur_enddate_timestamp: '.$recur_enddate); 73 73 if ($recur_enddate < $row[2]) { 74 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageList-> ERRO: Esse evento n ão será adicionado na lista porque o campo phpgw_cal_repeats.recur_enddate émenor que o campo phpgw_cal.datetime. Corrija o valor de um dos campos');74 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageList-> ERRO: Esse evento não será adicionado na lista porque o campo phpgw_cal_repeats.recur_enddate é menor que o campo phpgw_cal.datetime. Corrija o valor de um dos campos'); 75 75 continue; // Nao sincroniza este evento, porque a data final da recorrencia eh menor que a data inicial do evento. Eh o BD do Expresso que esta inconsistente. 76 76 } … … 91 91 if ($result_invalid_ref == FALSE) throw new Exception(pg_last_error($this->db)); 92 92 while ($row_invalid_ref = pg_fetch_row($result_invalid_ref)) { 93 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageList-> ERRO: Evento com campo reference inv álido (cal_id: '.$row_invalid_ref[0].', title: '.$row_invalid_ref[4].', reference: '.$row_invalid_ref[5].', last_update: '.date("d/m/Y G:i:s",substr($row_invalid_ref[1], 0, strlen($row[1])-3)).', last_update_timestamp: '.$row_invalid_ref[1].', datetime: '.date("d/m/Y G:i:s",$row_invalid_ref[2]).', datetime_timestamp: '.$row_invalid_ref[2].', cal_type: '.$row_invalid_ref[3].')');93 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageList-> ERRO: Evento com campo reference inválido (cal_id: '.$row_invalid_ref[0].', title: '.$row_invalid_ref[4].', reference: '.$row_invalid_ref[5].', last_update: '.date("d/m/Y G:i:s",substr($row_invalid_ref[1], 0, strlen($row[1])-3)).', last_update_timestamp: '.$row_invalid_ref[1].', datetime: '.date("d/m/Y G:i:s",$row_invalid_ref[2]).', datetime_timestamp: '.$row_invalid_ref[2].', cal_type: '.$row_invalid_ref[3].')'); 94 94 } 95 95 // Evento fora da faixa filtrada … … 107 107 debugLog("exception -> " . $e->getMessage() . " - ARQUIVO: " . $e->getFile() . " - LINHA: " . $e->getLine()); 108 108 } 109 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageList-> Fim normal da fun ção');109 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageList-> Fim normal da função'); 110 110 return $messages; 111 111 } … … 147 147 if($folderid != "calendar") return false; 148 148 try { 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 149 $result = pg_query($this->db,"BEGIN;"); 150 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 151 $result_calendar = pg_query($this->db, "select last_update from phpgw_cal where cal_id = " . $id . ";"); 152 if ($result_calendar == FALSE) throw new Exception(pg_last_error($this->db)); 153 while ($row_calendar = pg_fetch_row($result_calendar)) { 154 if(isset($row_calendar[0])) { 155 $message = array(); 156 $message["mod"] = substr($row_calendar[0], 0, strlen($row_calendar[0])-3); 157 $message["id"] = $id; 158 $message["flags"] = 1; 159 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::StatMessage-> mod: '.$message["mod"].', id: '.$message["id"]); 160 return $message; 161 } 162 } 163 $result = pg_query($this->db,"COMMIT;"); 164 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 165 165 } catch (Exception $e) { 166 166 pg_query($this->db,"ROLLBACK;"); 167 167 debugLog("exception -> " . $e->getMessage() . " - ARQUIVO: " . $e->getFile() . " - LINHA: " . $e->getLine()); 168 168 } 169 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::StatMessage: ERRO: N ão encontrou valor para o campo last_update para esse evento.');169 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::StatMessage: ERRO: Não encontrou valor para o campo last_update para esse evento.'); 170 170 return false; 171 171 } … … 186 186 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 187 187 if ($row = pg_fetch_row($result)) { 188 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO-> L êevento do DB para enviar para o celular (cal_id: '.$row[0].', title:'.$row[1].', location: '.$row[2].', mdatetime: '.$row[3].', datetime: '.$row[4].', edatetime: '.$row[5].', reference: '.$row[7].', isPublic: '.$row[8].')');188 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO-> Lê evento do DB para enviar para o celular (cal_id: '.$row[0].', title:'.$row[1].', location: '.$row[2].', mdatetime: '.$row[3].', datetime: '.$row[4].', edatetime: '.$row[5].', reference: '.$row[7].', isPublic: '.$row[8].')'); 189 189 if ($row[7] != 0) $has_parent_event = true; 190 190 else $has_parent_event = false; … … 236 236 } 237 237 } 238 $message->alldayevent = 0; // (0 - N ão(default), 1- Sim)238 $message->alldayevent = 0; // (0 - Não(default), 1- Sim) 239 239 $message->busystatus = 2; // 2 - Ocupado 240 240 //TODO: Tratar $message - timezone 241 // $tz = $this->_getGMTTZ();241 // $tz = $this->_getGMTTZ(); 242 242 $tz = array("bias" => 180, "stdbias" => 0, "dstbias" => -60, "dstendyear" => 0, "dstendmonth" => 2, "dstendday" => 0, "dstendweek" => 2, "dstendhour" => 2, "dstendminute" => 0, "dstendsecond" => 0, "dstendmillis" => 0, 243 "dststartyear" => 0, "dststartmonth" =>10, "dststartday" =>0, "dststartweek" => 3, "dststarthour" => 2, "dststartminute" => 0, "dststartsecond" => 0, "dststartmillis" => 0);243 "dststartyear" => 0, "dststartmonth" =>10, "dststartday" =>0, "dststartweek" => 3, "dststarthour" => 2, "dststartminute" => 0, "dststartsecond" => 0, "dststartmillis" => 0); 244 244 $message->timezone = base64_encode($this->_getSyncBlobFromTZ($tz)); 245 245 //TODO: Se necessario, tratar $message - meetingstatus … … 265 265 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 266 266 if ($row = pg_fetch_row($result)){ 267 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO-> L ê recorrência do evento (recur_type: '.$row[0].', recur_use_end: '.$row[1].', recur_enddate: '.$row[2].', recur_interval: '.$row[3].', recur_data: '.$row[4].', recur_exception: '.$row[5].')');267 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO-> Lê recorrência do evento (recur_type: '.$row[0].', recur_use_end: '.$row[1].', recur_enddate: '.$row[2].', recur_interval: '.$row[3].', recur_data: '.$row[4].', recur_exception: '.$row[5].')'); 268 268 $recur = new SyncRecurrence(); 269 269 // Converte os tipos do Expresso para os tipos do Protocolo ActiveSync … … 311 311 } 312 312 $message->recurrence = $recur; 313 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO-> Fim do Bloco - L ê recorrência do evento.');313 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO-> Fim do Bloco - Lê recorrência do evento.'); 314 314 } 315 315 … … 318 318 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 319 319 while ($row_recur_exception = pg_fetch_row($result)) { 320 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO: L ê evento único da recorrência com id: '.$row_recur_exception[0]);320 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO: Lê evento único da recorrência com id: '.$row_recur_exception[0]); 321 321 $recur_exception = $this->GetMessageDAO($row_recur_exception[0]); 322 322 if ($recur_exception instanceof SyncAppointment) { … … 324 324 array_push($message->exceptions, $recur_exception); 325 325 } 326 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO-> Fim do Bloco - L ê evento único da recorrência com id: '.$row_recur_exception[0]);326 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO-> Fim do Bloco - Lê evento único da recorrência com id: '.$row_recur_exception[0]); 327 327 } 328 328 … … 331 331 $array_timestamps_recur_deleted = explode(",",$row[5]); 332 332 foreach ($array_timestamps_recur_deleted as $timestamp_recur_deleted) { 333 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO: Timestamps dos eventos únicos da recorrência do tipo deletados: '.$timestamp_recur_deleted);333 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO: Timestamps dos eventos únicos da recorrência do tipo deletados: '.$timestamp_recur_deleted); 334 334 $recur_deleted = new SyncAppointment(); 335 335 $recur_deleted->deleted = '1'; … … 340 340 } 341 341 //TODO: Tratar Participantes do Evento 342 343 342 } 344 343 $result = pg_query($this->db,"COMMIT;"); … … 349 348 return; 350 349 } 351 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO-> Fim do Bloco - L êevento do DB para enviar para o celular: '.$id);350 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::GetMessageDAO-> Fim do Bloco - Lê evento do DB para enviar para o celular: '.$id); 352 351 return $message; 353 352 } … … 389 388 return false; 390 389 } 391 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog("CalendarExpresso::DeleteMessage-> Fim normal da Fun ção.");390 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog("CalendarExpresso::DeleteMessage-> Fim normal da Função."); 392 391 return true; 393 392 } … … 399 398 function ChangeMessageDAO($id, $message) { 400 399 debugLog('CalendarExpresso::ChangeMessageDAO('.$id.', ..)'); 401 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> O evento do celular ser áinserido/atualizado no BD com o ID: '.$id);400 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> O evento do celular será inserido/atualizado no BD com o ID: '.$id); 402 401 try { 403 402 $result = pg_query($this->db,"BEGIN;"); … … 543 542 //TODO: Implementar para os tipos 3 e 6. O Expresso ainda nao suporta esses tipos :-( 544 543 if (isset($message->recurrence) and ($message->recurrence->type == 0 or $message->recurrence->type == 1 or $message->recurrence->type == 2 or $message->recurrence->type == 5)) { 545 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> O Evento éRecorrente.');544 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> O Evento é Recorrente.'); 546 545 switch ($message->recurrence->type) { 547 546 case 0: //repeticao diaria … … 562 561 break; 563 562 } 564 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Recorr ência-> recur_type: '.$arrayRecur["recur_type"]);563 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Recorrência-> recur_type: '.$arrayRecur["recur_type"]); 565 564 if (isset($message->recurrence->interval)) { 566 565 $arrayRecur["recur_interval"] = $message->recurrence->interval; 567 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Recorr ência-> recur_interval: '.$arrayRecur["recur_interval"]);566 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Recorrência-> recur_interval: '.$arrayRecur["recur_interval"]); 568 567 } 569 568 if ($message->recurrence->type == 1 or $message->recurrence->type == 3 or $message->recurrence->type == 6) { 570 569 if (isset($message->recurrence->dayofweek)) { 571 570 $arrayRecur["recur_data"] = $message->recurrence->dayofweek; 572 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Recorr ência-> recur_data: '.$arrayRecur["recur_data"]);571 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Recorrência-> recur_data: '.$arrayRecur["recur_data"]); 573 572 /*$day = $message->recurrence->dayofweek; 574 573 $day_of_week_counter = 0; … … 615 614 $arrayRecur["recur_enddate"] = 1893283200; // Se nao tem data de termino seta para 30/12/2029 616 615 } 617 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Recorr ência-> recur_enddate: '.$arrayRecur["recur_enddate"]);616 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Recorrência-> recur_enddate: '.$arrayRecur["recur_enddate"]); 618 617 619 618 // Trata excecoes da recorrencia … … 621 620 // Tem Excecoes de recorrencia do tipo Edicao 622 621 // Verifica se ja existe o registro do evento de excecao de recorrencia na tabela phpgw_cal 623 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Evento tem exce ção de recorrência');622 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Evento tem exceção de recorrência'); 624 623 $recur_exception_changed_ids = ""; 625 624 $recur_exception_deleted_starttimes = ""; … … 643 642 $except_description_from_DB = $row[2]; 644 643 $found_except_cal_id = true; 645 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Achou o evento na tabela phpgw_cal, vai ATUALIZAR a exce ção da recorrência nessa tabela');644 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Achou o evento na tabela phpgw_cal, vai ATUALIZAR a exceção da recorrência nessa tabela'); 646 645 } 647 646 } … … 653 652 if(isset($row[0])) { 654 653 $found_except_cal_user = true; 655 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Achou o evento na tabela phpgw_cal_user, vai ATUALIZAR a exce ção da recorrência nessa tabela');654 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Achou o evento na tabela phpgw_cal_user, vai ATUALIZAR a exceção da recorrência nessa tabela'); 656 655 } 657 656 } … … 661 660 if(isset($message->uid)) { 662 661 $arrayExceptCal["uid"] = $this->truncateString(utf8_decode($message->uid),255); 663 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exce ção De Recorrência-> uid: '.$arrayExceptCal["uid"]);662 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exceção De Recorrência-> uid: '.$arrayExceptCal["uid"]); 664 663 } 665 664 if(isset($recur_exception->subject)) { … … 668 667 $arrayExceptCal["title"] = $this->truncateString(utf8_decode($message->subject),299); 669 668 } 670 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exce ção De Recorrência-> title: '.$arrayExceptCal["title"]);669 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exceção De Recorrência-> title: '.$arrayExceptCal["title"]); 671 670 if(isset($recur_exception->location)) { 672 671 $arrayExceptCal["location"] = $this->truncateString(utf8_decode($recur_exception->location),255); … … 674 673 $arrayExceptCal["location"] = $this->truncateString(utf8_decode($message->location),255); 675 674 } 676 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exce ção De Recorrência-> location: '.$arrayExceptCal["location"]);675 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exceção De Recorrência-> location: '.$arrayExceptCal["location"]); 677 676 if(isset($recur_exception->dtstamp)) { 678 677 $arrayExceptCal["mdatetime"] = $recur_exception->dtstamp; … … 680 679 $arrayExceptCal["mdatetime"] = $message->dtstamp; 681 680 } 682 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exce ção De Recorrência-> mdatetime: '.$arrayExceptCal["mdatetime"]);681 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exceção De Recorrência-> mdatetime: '.$arrayExceptCal["mdatetime"]); 683 682 if(isset($recur_exception->starttime)) { 684 683 $arrayExceptCal["datetime"] = $recur_exception->starttime; … … 686 685 $arrayExceptCal["datetime"] = $message->starttime; 687 686 } 688 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exce ção De Recorrência-> datetime: '.$arrayExceptCal["datetime"]);687 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exceção De Recorrência-> datetime: '.$arrayExceptCal["datetime"]); 689 688 if(isset($recur_exception->endtime)) { 690 689 $arrayExceptCal["edatetime"] = $recur_exception->endtime; … … 692 691 $arrayExceptCal["edatetime"] = $message->endtime; 693 692 } 694 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exce ção De Recorrência-> edatetime: '.$arrayExceptCal["edatetime"]);693 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exceção De Recorrência-> edatetime: '.$arrayExceptCal["edatetime"]); 695 694 if(isset($recur_exception->sensitivity) and $recur_exception->sensitivity == 0) { 696 695 $arrayExceptCal["is_public"] = 1; // 1 - Normal … … 700 699 $arrayExceptCal["is_public"] = 1; // 1 - Normal 701 700 }else $arrayExceptCal["is_public"] = 0; // 0 - Privado 702 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exce ção De Recorrência-> is_public: '.$arrayExceptCal["is_public"]);701 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exceção De Recorrência-> is_public: '.$arrayExceptCal["is_public"]); 703 702 if (isset($recur_exception->body)) { 704 703 $arrayExceptCal["description"] = utf8_decode($recur_exception->body); … … 738 737 } 739 738 } 740 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exce ção De Recorrência-> category: '.$arrayExceptCal["category"]);739 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Exceção De Recorrência-> category: '.$arrayExceptCal["category"]); 741 740 //TODO: Converter eventos que sao alldayevent para iniciar as 0:00hs e terminar as 23:59hs. Isso porque o Expresso nao suporta alldayevents 742 741 // if(isset($message->alldayevent)) { … … 752 751 $result = pg_insert($this->db, 'phpgw_cal', $arrayExceptCal); 753 752 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 754 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Evento de Exce ção da Recorrência INSERIDO na tabela phpgw_cal com cal_id: '.$arrayExceptCal["cal_id"]);753 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Evento de Exceção da Recorrência INSERIDO na tabela phpgw_cal com cal_id: '.$arrayExceptCal["cal_id"]); 755 754 } else { 756 755 $result = pg_update($this->db, 'phpgw_cal', $arrayExceptCal, array('cal_id' => $except_cal_id)); 757 756 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 758 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Evento de Exce ção da Recorrência ATUALIZADO na tabela phpgw_cal');757 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Evento de Exceção da Recorrência ATUALIZADO na tabela phpgw_cal'); 759 758 } 760 759 … … 768 767 $result = pg_insert($this->db, 'phpgw_cal_user', $arrayExceptCalUser); 769 768 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 770 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Evento de Exce ção da Recorrência INSERIDO na tabela phpgw_cal_user com cal_id: '.$arrayExceptCalUser["cal_id"]);769 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Evento de Exceção da Recorrência INSERIDO na tabela phpgw_cal_user com cal_id: '.$arrayExceptCalUser["cal_id"]); 771 770 } else { 772 771 $result = pg_update($this->db, 'phpgw_cal_user', $arrayExceptCalUser, array('cal_id' => $except_cal_id, 'cal_login' => $this->_uidnumber)); 773 772 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 774 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Evento de Exce ção da Recorrência ATUALIZADO na tabela phpgw_cal_user');773 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Evento de Exceção da Recorrência ATUALIZADO na tabela phpgw_cal_user'); 775 774 } 776 775 if ($recur_exception_changed_ids == "") { … … 790 789 //Tem Excecoes de recorrencia do tipo Exclusao 791 790 $arrayRecur["recur_exception"] = $recur_exception_deleted_starttimes; 792 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Evento tem exce ção de recorrência do tipo exclusão com os seguintes starttimes: '.$recur_exception_deleted_starttimes);791 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Evento tem exceção de recorrência do tipo exclusão com os seguintes starttimes: '.$recur_exception_deleted_starttimes); 793 792 } else { 794 793 $arrayRecur["recur_exception"] = ""; 795 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> N ão tem exceção de recorrência do tipo exclusão para esse evento');794 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Não tem exceção de recorrência do tipo exclusão para esse evento'); 796 795 } 797 796 if ($recur_exception_changed_ids == "") { … … 801 800 $result = pg_query($this->db, "delete from phpgw_cal where reference = " . $cal_id . ";"); 802 801 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 803 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> N ão tem exceção de recorrência, então deleta possíveis eventos de exceção de recorrência criados anteriormente para esse evento.');802 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Não tem exceção de recorrência, então deleta possÃveis eventos de exceção de recorrência criados anteriormente para esse evento.'); 804 803 } else { 805 804 //Deleta as excecoes da recorrencia, exceto as inseridas/atualizadas acima … … 808 807 $result = pg_query($this->db, "delete from phpgw_cal where reference = " . $cal_id . " and cal_id not in (" . $recur_exception_changed_ids . ");"); 809 808 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 810 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Deleta as ex çeções da recorrência, exceto as inseridas/atualizadas pelo celular com os seguintes cal_id:'.$recur_exception_changed_ids);809 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Deleta as exçeções da recorrência, exceto as inseridas/atualizadas pelo celular com os seguintes cal_id:'.$recur_exception_changed_ids); 811 810 } 812 811 } else { … … 817 816 $result = pg_query($this->db, "delete from phpgw_cal where reference = " . $cal_id . ";"); 818 817 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 819 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> N ão tem exceção de recorrência, então deleta possíveis eventos de exceção de recorrência criados anteriormente para esse evento..');818 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Não tem exceção de recorrência, então deleta possÃveis eventos de exceção de recorrência criados anteriormente para esse evento..'); 820 819 } 821 820 if (!$found_cal_repeats){ … … 823 822 $result = pg_insert($this->db, 'phpgw_cal_repeats', $arrayRecur); 824 823 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 825 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Recorr ência INSERIDA na tabela phpgw_cal_repeats com cal_id: '.$arrayRecur["cal_id"]);824 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Recorrência INSERIDA na tabela phpgw_cal_repeats com cal_id: '.$arrayRecur["cal_id"]); 826 825 } else { 827 826 $result = pg_update($this->db, 'phpgw_cal_repeats', $arrayRecur, array('cal_id' => $cal_id)); 828 827 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 829 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Recorr ência ATUALIZADA na tabela phpgw_cal_repeats');828 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Recorrência ATUALIZADA na tabela phpgw_cal_repeats'); 830 829 } 831 830 } elseif ($found_cal_id) { … … 837 836 $result = pg_query($this->db, "delete from phpgw_cal_repeats where cal_id = " . $cal_id . ";"); 838 837 if ($result == FALSE) throw new Exception(pg_last_error($this->db)); 839 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> N ão tem recorrência, então deleta possíveis eventos de recorrência criados anteriormente para esse evento');838 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Não tem recorrência, então deleta possÃveis eventos de recorrência criados anteriormente para esse evento'); 840 839 } 841 840 $result = pg_query($this->db,"COMMIT;"); … … 847 846 return false; 848 847 } 849 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Fim normal da Fun ção');848 if (TRACE_UID !== false and (TRACE_TYPE == 'CALENDAR' or TRACE_TYPE == 'ALL')) traceLog('CalendarExpresso::ChangeMessageDAO-> Fim normal da Função'); 850 849 return $id; 851 850 } … … 917 916 918 917 function removeAccents($data){ 919 $data = strtr($data,"ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÜÚÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùüúþÿ","aaaaaaaceeeeiiii noooooxouuutbaaaaaaaceeeeiiii nooooo/ouuuty"); 918 $data = strtr($data,"ÃÃÃÃÃà 919 ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃà áâãÀåÊçÚéêëìÃîïðñòóÎõö÷ÞùÌúßÿ","aaaaaaaceeeeiiii noooooxouuutbaaaaaaaceeeeiiii nooooo/ouuuty"); 920 920 return $data; 921 921 } … … 944 944 function _getGMTTZ() { 945 945 //$tz = array("bias" => 0, "stdbias" => 0, "dstbias" => 0, "dstendyear" => 0, "dstendmonth" => 2, "dstendday" => 0, "dstendweek" => 2, "dstendhour" => 2, "dstendminute" => 0, "dstendsecond" => 0, "dstendmillis" => 0, 946 // 947 $tz = array("bias" => 120, "stdbias" => 0, "dstbias" => -60, "dstendyear" => 0, "dstendmonth" => 2, "dstendday" => 0, "dstendweek" => 2, "dstendhour" => 2, "dstendminute" => 0, "dstendsecond" => 0, "dstendmillis" => 0, 948 "dststartyear" => 0, "dststartmonth" =>10, "dststartday" =>0, "dststartweek" => 3, "dststarthour" => 2, "dststartminute" => 0, "dststartsecond" => 0, "dststartmillis" => 0);946 //"dststartyear" => 0, "dststartmonth" =>10, "dststartday" =>0, "dststartweek" => 3, "dststarthour" => 2, "dststartminute" => 0, "dststartsecond" => 0, "dststartmillis" => 0); 947 $tz = array("bias" => 120, "stdbias" => 0, "dstbias" => -60, "dstendyear" => 0, "dstendmonth" => 2, "dstendday" => 0, "dstendweek" => 2, "dstendhour" => 2, "dstendminute" => 0, "dstendsecond" => 0, "dstendmillis" => 0, "dststartyear" => 0, "dststartmonth" =>10, "dststartday" =>0, "dststartweek" => 3, "dststarthour" => 2, "dststartminute" => 0, "dststartsecond" => 0, "dststartmillis" => 0); 948 949 949 return $tz; 950 950 } -
contrib/z-push/backend/imap.php
r4619 r4898 9 9 * Created : 10.10.2007 10 10 * 11 * ï¿œZarafa Deutschland GmbH, www.zarafaserver.de11 * Zarafa Deutschland GmbH, www.zarafaserver.de 12 12 * This file is distributed under GPL v2. 13 13 * Consult LICENSE file for details … … 91 91 * the new message as any other new message in a folder. 92 92 */ 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 foreach($message->headers as $k => $v) { 125 if ($k == "subject" || $k == "to" || $k == "cc" || $k == "bcc") 126 continue; 127 128 if ($k == "content-type") { 129 // if the message is a multipart message, then we should use the sent body 130 if (preg_match("/multipart/i", $v)) { 131 $use_orgbody = true; 132 $org_boundary = $message->ctype_parameters["boundary"];133 } 134 135 // save the original content-type header for the body part when forwarding 136 if ($forward && !$use_orgbody) { 137 $forward_h_ct = $v; 138 continue;139 } 140 141 // set charset always to utf-8 142 $org_charset = $v; 143 $v = preg_replace("/charset=([A-Za-z0-9-\"']+)/", "charset=\"utf-8\"", $v);144 } 145 146 if ($k == "content-transfer-encoding") { 147 // if the content was base64 encoded, encode the body again when sending 148 if (trim($v) == "base64") $body_base64 = true; 149 150 // save the original encoding header for the body part when forwarding 151 if ($forward) { 152 $forward_h_cte = $v; 153 continue;154 } 155 156 157 // check if "from"-header is set, do nothing if it's set 158 // else set it to IMAP_DEFAULTFROM 159 if ($k == "from") { 160 if (trim($v)) {161 $changedfrom = true; 162 } elseif (! trim($v) && IMAP_DEFAULTFROM) { 163 $changedfrom = true; 164 if (IMAP_DEFAULTFROM == 'username') $v = $this->_username;165 else if (IMAP_DEFAULTFROM == 'domain') $v = $this->_domain;166 else $v = $this->_username . IMAP_DEFAULTFROM;167 $envelopefrom = "-f$v";168 } 169 170 171 // check if "Return-Path"-header is set 172 if ($k == "return-path") { 173 $returnPathSet = true; 174 if (! trim($v) && IMAP_DEFAULTFROM) { 175 if (IMAP_DEFAULTFROM == 'username') $v = $this->_username; 176 else if (IMAP_DEFAULTFROM == 'domain') $v = $this->_domain;177 else $v = $this->_username . IMAP_DEFAULTFROM;178 } 179 180 181 // all other headers stay 182 if ($headers) $headers .= "\n"; 183 $headers .= ucfirst($k) . ": ". $v;184 } 185 186 // set "From" header if not set on the device 187 if(IMAP_DEFAULTFROM && !$changedfrom){ 188 if (IMAP_DEFAULTFROM == 'username') $v = $this->_username; 189 else if (IMAP_DEFAULTFROM == 'domain') $v = $this->_domain;190 else $v = $this->_username . IMAP_DEFAULTFROM;191 if ($headers) $headers .= "\n";192 $headers .= 'From: '.$v;193 $envelopefrom = "-f$v";194 } 195 196 // set "Return-Path" header if not set on the device 197 if(IMAP_DEFAULTFROM && !$returnPathSet){ 198 if (IMAP_DEFAULTFROM == 'username') $v = $this->_username; 199 else if (IMAP_DEFAULTFROM == 'domain') $v = $this->_domain;200 else $v = $this->_username . IMAP_DEFAULTFROM;201 if ($headers) $headers .= "\n";202 $headers .= 'Return-Path: '.$v;203 } 204 205 // if this is a multipart message with a boundary, we must use the original body 206 if ($use_orgbody) { 207 list(,$body) = $mobj->_splitBodyHeader($rfc822); 208 $repl_body = $this->getBody($message); 209 if ($message->parts[0]->headers["content-transfer-encoding"] == "base64") $multipart_text_cte_base64 = true; 210 else $multipart_text_cte_base64 = false;211 } 212 else 213 $body = $this->getBody($message); 214 215 // reply 216 if ($reply && $parent) { 217 $this->imap_reopenFolder($parent); 218 // receive entire mail (header + body) to decode body correctly 219 $origmail = @imap_fetchheader($this->_mbox, $reply, FT_UID) . @imap_body($this->_mbox, $reply, FT_PEEK | FT_UID); 220 221 $mobj2 = new Mail_mimeDecode($origmail); 222 // receive only body 223 $body .= $this->getBody($mobj2->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8'))); 224 // unset mimedecoder & origmail - free memory 225 unset($mobj2); 226 unset($origmail);227 } 228 229 // encode the body to base64 if it was sent originally in base64 by the pda 230 // contrib - chunk base64 encoded body 231 if ($body_base64 && !$forward) $body = chunk_split(base64_encode($body)); 232 233 234 // forward 235 if ($forward && $parent) { 236 $this->imap_reopenFolder($parent); 237 // receive entire mail (header + body) 238 $origmail = @imap_fetchheader($this->_mbox, $forward, FT_UID) . @imap_body($this->_mbox, $forward, FT_PEEK | FT_UID); 239 240 //if (!defined('IMAP_INLINE_FORWARD') || IMAP_INLINE_FORWARD === false) { 241 242 243 244 245 246 247 248 249 250 251 } 252 else { 253 $mobj2 = new Mail_mimeDecode($origmail);254 $mess2 = $mobj2->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8')); 255 256 if (!$use_orgbody) 257 $nbody = $body; 258 else 259 $nbody = $repl_body; 260 261 $nbody .= "\r\n\r\n";262 $nbody .= "-----Original Message-----\r\n"; 263 if(isset($mess2->headers['from'])) 264 $nbody .= "From: " . $mess2->headers['from'] . "\r\n"; 265 if(isset($mess2->headers['to']) && strlen($mess2->headers['to']) > 0) 266 $nbody .= "To: " . $mess2->headers['to'] . "\r\n"; 267 if(isset($mess2->headers['cc']) && strlen($mess2->headers['cc']) > 0) 268 $nbody .= "Cc: " . $mess2->headers['cc'] . "\r\n"; 269 if(isset($mess2->headers['date'])) 270 $nbody .= "Sent: " . $mess2->headers['date'] . "\r\n"; 271 if(isset($mess2->headers['subject'])) 272 $nbody .= "Subject: " . $mess2->headers['subject'] . "\r\n"; 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 $body = str_replace(base64_encode($repl_body), base64_encode($nbody), $body); } 293 294 else 295 $body = $nbody; 296 297 298 if(isset($mess2->parts)) { 299 $attached = false; 300 301 if ($org_boundary) { 302 $att_boundary = $org_boundary; 303 // cut end boundary from body 304 $body = substr($body, 0, strrpos($body, "--$att_boundary--")); 305 } 306 else { 307 $att_boundary = strtoupper(md5(uniqid(time()))); 308 // add boundary headers 309 $headers .= "\n" . "Content-Type: multipart/mixed; boundary=$att_boundary"; 310 $multipartmixed = true;311 } 312 313 foreach($mess2->parts as $part) { 314 if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) {315 316 if(isset($part->d_parameters['filename'])) 317 $attname = $part->d_parameters['filename']; 318 else if(isset($part->ctype_parameters['name'])) 319 $attname = $part->ctype_parameters['name']; 320 else if(isset($part->headers['content-description'])) 321 $attname = $part->headers['content-description']; 322 else $attname = "unknown attachment";323 324 // ignore html content 325 if ($part->ctype_primary == "text" && $part->ctype_secondary == "html") { 326 continue; 327 } 328 // 329 if ($use_orgbody || $attached) { 330 $body .= $this->enc_attach_file($att_boundary, $attname, strlen($part->body),$part->body, $part->ctype_primary ."/". $part->ctype_secondary); 331 } 332 // first attachment 333 else { 334 $encmail = $body; 335 $attached = true;336 $body = $this->enc_multipart($att_boundary, $body, $forward_h_ct, $forward_h_cte);337 $body .= $this->enc_attach_file($att_boundary, $attname, strlen($part->body),$part->body, $part->ctype_primary ."/". $part->ctype_secondary);338 } 339 340 341 if ($multipartmixed) { 342 //this happens if a multipart/alternative message is forwarded 343 //then it's a multipart/mixed message which consists of: 344 //1. text/plain part which was written on the mobile 345 //2. multipart/alternative part which is the original message346 //$body = "This is a message with multiple parts in MIME format.\n--". 347 // $att_boundary.348 // "\nContent-Type: $forward_h_ct\nContent-Transfer-Encoding: $forward_h_cte\n\n".349 // (($body_base64) ? chunk_split(base64_encode($message->body)) : rtrim($message->body)).350 // "\n--".$att_boundary.351 // "\nContent-Type: {$mess2->headers['content-type']}\n\n".352 // @imap_body($this->_mbox, $forward, FT_PEEK | FT_UID)."\n\n"; 353 $body = "\n--". 354 $att_boundary.355 "\nContent-Type: $forward_h_ct\nContent-Transfer-Encoding: $forward_h_cte\n\n".356 $body; 357 } 358 359 $body .= "--$att_boundary--\n\n"; 360 } 361 362 unset($mobj2); 363 }364 365 // unset origmail - free memory 366 unset($origmail); 367 368 } 369 370 // remove carriage-returns from body 371 $body = str_replace("\r\n", "\n", $body); 372 373 if (!$multipartmixed) { 374 if (!empty($forward_h_ct)) $headers .= "\nContent-Type: $forward_h_ct"; 375 if (!empty($forward_h_cte)) $headers .= "\nContent-Transfer-Encoding: $forward_h_cte";376 } 377 //advanced debugging 378 debugLog("IMAP-SendMail: parsed message: ". print_r($message,1)); 379 debugLog("IMAP-SendMail: headers: $headers");380 debugLog("IMAP-SendMail: subject: {$message->headers["subject"]}");381 debugLog("IMAP-SendMail: body: $body");382 383 if (!defined('IMAP_USE_IMAPMAIL') || IMAP_USE_IMAPMAIL == true) { 384 $send = @imap_mail ( $toaddr, $message->headers["subject"], $body, $headers, $ccaddr, $bccaddr); 385 } 386 else { 387 if (!empty($ccaddr)) $headers .= "\nCc: $ccaddr"; 388 if (!empty($bccaddr)) $headers .= "\nBcc: $bccaddr";389 $send = @mail ( $toaddr, $message->headers["subject"], $body, $headers, $envelopefrom );390 } 391 392 // email sent? 393 if (!$send) { 394 debugLog("The email could not be sent. Last-IMAP-error: ". imap_last_error()); 395 } 396 397 // add message to the sent folder 398 // build complete headers 399 $headers .= "\nTo: $toaddr"; 400 $headers .= "\nSubject: " . $message->headers["subject"];401 402 if (!defined('IMAP_USE_IMAPMAIL') || IMAP_USE_IMAPMAIL == true) { 403 if (!empty($ccaddr)) $headers .= "\nCc: $ccaddr"; 404 if (!empty($bccaddr)) $headers .= "\nBcc: $bccaddr";405 } 406 debugLog("IMAP-SendMail: complete headers: $headers"); 407 408 $asf = false; 409 if ($this->_sentID) { 410 $asf = $this->addSentMessage($this->_sentID, $headers, $body); 411 } 412 else if (IMAP_SENTFOLDER) { 413 $asf = $this->addSentMessage(IMAP_SENTFOLDER, $headers, $body); 414 debugLog("IMAP-SendMail: Outgoing mail saved in configured 'Sent' folder '".IMAP_SENTFOLDER."': ". (($asf)?"success":"failed"));415 } 416 // No Sent folder set, try defaults 417 else { 418 debugLog("IMAP-SendMail: No Sent mailbox set"); 419 if($this->addSentMessage("INBOX.Sent", $headers, $body)) { 420 debugLog("IMAP-SendMail: Outgoing mail saved in 'INBOX.Sent'"); 421 $asf = true;422 } 423 else if ($this->addSentMessage("Sent", $headers, $body)) { 424 debugLog("IMAP-SendMail: Outgoing mail saved in 'Sent'"); 425 $asf = true;426 } 427 else if ($this->addSentMessage("Sent Items", $headers, $body)) { 428 debugLog("IMAP-SendMail: Outgoing mail saved in 'Sent Items'"); 429 $asf = true;430 } 431 432 433 // unset mimedecoder - free memory 434 unset($mobj); 435 return ($send && $asf);436 } 437 93 function SendMail($rfc822, $forward = false, $reply = false, $parent = false) { 94 debugLog("IMAP-SendMail: for: $forward reply: $reply parent: $parent RFC822: \n". $rfc822 ); 95 96 $mobj = new Mail_mimeDecode($rfc822); 97 $message = $mobj->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8')); 98 99 $Mail_RFC822 = new Mail_RFC822(); 100 $toaddr = $ccaddr = $bccaddr = ""; 101 if(isset($message->headers["to"])) 102 $toaddr = $this->parseAddr($Mail_RFC822->parseAddressList($message->headers["to"])); 103 if(isset($message->headers["cc"])) 104 $ccaddr = $this->parseAddr($Mail_RFC822->parseAddressList($message->headers["cc"])); 105 if(isset($message->headers["bcc"])) 106 $bccaddr = $this->parseAddr($Mail_RFC822->parseAddressList($message->headers["bcc"])); 107 108 // save some headers when forwarding mails (content type & transfer-encoding) 109 $headers = ""; 110 $forward_h_ct = ""; 111 $forward_h_cte = ""; 112 $envelopefrom = ""; 113 114 $use_orgbody = false; 115 116 // clean up the transmitted headers 117 // remove default headers because we are using imap_mail 118 $changedfrom = false; 119 $returnPathSet = false; 120 $body_base64 = false; 121 $org_charset = ""; 122 $org_boundary = false; 123 $multipartmixed = false; 124 125 foreach($message->headers as $k => $v) { 126 if ($k == "subject" || $k == "to" || $k == "cc" || $k == "bcc") 127 continue; 128 129 if ($k == "content-type") { 130 // if the message is a multipart message, then we should use the sent body 131 if (preg_match("/multipart/i", $v)) { 132 $use_orgbody = true; 133 $org_boundary = $message->ctype_parameters["boundary"]; 134 } 135 136 // save the original content-type header for the body part when forwarding 137 if ($forward && !$use_orgbody) { 138 $forward_h_ct = $v; 139 continue; 140 } 141 142 // set charset always to utf-8 143 $org_charset = $v; 144 $v = preg_replace("/charset=([A-Za-z0-9-\"']+)/", "charset=\"utf-8\"", $v); 145 } 146 147 if ($k == "content-transfer-encoding") { 148 // if the content was base64 encoded, encode the body again when sending 149 if (trim($v) == "base64") $body_base64 = true; 150 151 // save the original encoding header for the body part when forwarding 152 if ($forward) { 153 $forward_h_cte = $v; 154 continue; 155 } 156 } 157 158 // check if "from"-header is set, do nothing if it's set 159 // else set it to IMAP_DEFAULTFROM 160 if ($k == "from") { 161 if (trim($v)) { 162 $changedfrom = true; 163 } elseif (! trim($v) && IMAP_DEFAULTFROM) { 164 $changedfrom = true; 165 if (IMAP_DEFAULTFROM == 'username') $v = $this->_username; 166 else if (IMAP_DEFAULTFROM == 'domain') $v = $this->_domain; 167 else $v = $this->_username . IMAP_DEFAULTFROM; 168 $envelopefrom = "-f$v"; 169 } 170 } 171 172 // check if "Return-Path"-header is set 173 if ($k == "return-path") { 174 $returnPathSet = true; 175 if (! trim($v) && IMAP_DEFAULTFROM) { 176 if (IMAP_DEFAULTFROM == 'username') $v = $this->_username; 177 else if (IMAP_DEFAULTFROM == 'domain') $v = $this->_domain; 178 else $v = $this->_username . IMAP_DEFAULTFROM; 179 } 180 } 181 182 // all other headers stay 183 if ($headers) $headers .= "\n"; 184 $headers .= ucfirst($k) . ": ". $v; 185 } 186 187 // set "From" header if not set on the device 188 if(IMAP_DEFAULTFROM && !$changedfrom){ 189 if (IMAP_DEFAULTFROM == 'username') $v = $this->_username; 190 else if (IMAP_DEFAULTFROM == 'domain') $v = $this->_domain; 191 else $v = $this->_username . IMAP_DEFAULTFROM; 192 if ($headers) $headers .= "\n"; 193 $headers .= 'From: '.$v; 194 $envelopefrom = "-f$v"; 195 } 196 197 // set "Return-Path" header if not set on the device 198 if(IMAP_DEFAULTFROM && !$returnPathSet){ 199 if (IMAP_DEFAULTFROM == 'username') $v = $this->_username; 200 else if (IMAP_DEFAULTFROM == 'domain') $v = $this->_domain; 201 else $v = $this->_username . IMAP_DEFAULTFROM; 202 if ($headers) $headers .= "\n"; 203 $headers .= 'Return-Path: '.$v; 204 } 205 206 // if this is a multipart message with a boundary, we must use the original body 207 if ($use_orgbody) { 208 list(,$body) = $mobj->_splitBodyHeader($rfc822); 209 $repl_body = $this->getBody($message); 210 if ($message->parts[0]->headers["content-transfer-encoding"] == "base64") $multipart_text_cte_base64 = true; 211 else $multipart_text_cte_base64 = false; 212 } 213 else 214 $body = $this->getBody($message); 215 216 // reply 217 if ($reply && $parent) { 218 $this->imap_reopenFolder($parent); 219 // receive entire mail (header + body) to decode body correctly 220 $origmail = @imap_fetchheader($this->_mbox, $reply, FT_UID) . @imap_body($this->_mbox, $reply, FT_PEEK | FT_UID); 221 222 $mobj2 = new Mail_mimeDecode($origmail); 223 // receive only body 224 $body .= $this->getBody($mobj2->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8'))); 225 // unset mimedecoder & origmail - free memory 226 unset($mobj2); 227 unset($origmail); 228 } 229 230 // encode the body to base64 if it was sent originally in base64 by the pda 231 // contrib - chunk base64 encoded body 232 if ($body_base64 && !$forward) $body = chunk_split(base64_encode($body)); 233 234 235 // forward 236 if ($forward && $parent) { 237 $this->imap_reopenFolder($parent); 238 // receive entire mail (header + body) 239 $origmail = @imap_fetchheader($this->_mbox, $forward, FT_UID) . @imap_body($this->_mbox, $forward, FT_PEEK | FT_UID); 240 241 if (defined('IMAP_INLINE_FORWARD') && IMAP_INLINE_FORWARD === false) { 242 // contrib - chunk base64 encoded body 243 if ($body_base64) $body = chunk_split(base64_encode($body)); 244 //use original boundary if it's set 245 $boundary = ($org_boundary) ? $org_boundary : false; 246 // build a new mime message, forward entire old mail as file 247 list($aheader, $body) = $this->mail_attach("forwarded_message.eml",strlen($origmail),$origmail, $body, $forward_h_ct, $forward_h_cte,$boundary); 248 // add boundary headers 249 $headers .= "\n" . $aheader; 250 } 251 else { 252 $mobj2 = new Mail_mimeDecode($origmail); 253 $mess2 = $mobj2->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8')); 254 255 if (!$use_orgbody) 256 $nbody = $body; 257 else 258 $nbody = $repl_body; 259 260 $nbody .= "\r\n\r\n"; 261 $nbody .= "-----Original Message-----\r\n"; 262 if(isset($mess2->headers['from'])) 263 $nbody .= "From: " . $mess2->headers['from'] . "\r\n"; 264 if(isset($mess2->headers['to']) && strlen($mess2->headers['to']) > 0) 265 $nbody .= "To: " . $mess2->headers['to'] . "\r\n"; 266 if(isset($mess2->headers['cc']) && strlen($mess2->headers['cc']) > 0) 267 $nbody .= "Cc: " . $mess2->headers['cc'] . "\r\n"; 268 if(isset($mess2->headers['date'])) 269 $nbody .= "Sent: " . $mess2->headers['date'] . "\r\n"; 270 if(isset($mess2->headers['subject'])) 271 $nbody .= "Subject: " . $mess2->headers['subject'] . "\r\n"; 272 273 $nbody .= "\r\n"; 274 $nbody .= $this->getBody($mess2); 275 276 if ($body_base64) { 277 // contrib - chunk base64 encoded body 278 $nbody = chunk_split(base64_encode($nbody)); 279 if ($use_orgbody) 280 // contrib - chunk base64 encoded body 281 $repl_body = chunk_split(base64_encode($repl_body)); 282 } 283 284 if ($use_orgbody) { 285 debugLog("-------------------"); 286 debugLog("old:\n'$repl_body'\nnew:\n'$nbody'\nund der body:\n'$body'"); 287 //$body is quoted-printable encoded while $repl_body and $nbody are plain text, 288 //so we need to decode $body in order replace to take place 289 if (!$multipart_text_cte_base64) { 290 $body = str_replace($repl_body, $nbody, quoted_printable_decode($body)); 291 } else { 292 $body = str_replace(base64_encode($repl_body), base64_encode($nbody), $body); 293 } 294 } 295 else 296 $body = $nbody; 297 298 299 if(isset($mess2->parts)) { 300 $attached = false; 301 302 if ($org_boundary) { 303 $att_boundary = $org_boundary; 304 // cut end boundary from body 305 $body = substr($body, 0, strrpos($body, "--$att_boundary--")); 306 } 307 else { 308 $att_boundary = strtoupper(md5(uniqid(time()))); 309 // add boundary headers 310 $headers .= "\n" . "Content-Type: multipart/mixed; boundary=$att_boundary"; 311 $multipartmixed = true; 312 } 313 314 foreach($mess2->parts as $part) { 315 if(isset($part->disposition) && ($part->disposition == "attachment" || $part->disposition == "inline")) { 316 317 if(isset($part->d_parameters['filename'])) 318 $attname = $part->d_parameters['filename']; 319 else if(isset($part->ctype_parameters['name'])) 320 $attname = $part->ctype_parameters['name']; 321 else if(isset($part->headers['content-description'])) 322 $attname = $part->headers['content-description']; 323 else $attname = "unknown attachment"; 324 325 // ignore html content 326 if ($part->ctype_primary == "text" && $part->ctype_secondary == "html") { 327 continue; 328 } 329 // 330 if ($use_orgbody || $attached) { 331 $body .= $this->enc_attach_file($att_boundary, $attname, strlen($part->body),$part->body, $part->ctype_primary ."/". $part->ctype_secondary); 332 } 333 // first attachment 334 else { 335 $encmail = $body; 336 $attached = true; 337 $body = $this->enc_multipart($att_boundary, $body, $forward_h_ct, $forward_h_cte); 338 $body .= $this->enc_attach_file($att_boundary, $attname, strlen($part->body),$part->body, $part->ctype_primary ."/". $part->ctype_secondary); 339 } 340 } 341 } 342 if ($multipartmixed) { 343 //this happens if a multipart/alternative message is forwarded 344 //then it's a multipart/mixed message which consists of: 345 //1. text/plain part which was written on the mobile 346 //2. multipart/alternative part which is the original message 347 //$body = "This is a message with multiple parts in MIME format.\n--". 348 // $att_boundary. 349 // "\nContent-Type: $forward_h_ct\nContent-Transfer-Encoding: $forward_h_cte\n\n". 350 // (($body_base64) ? chunk_split(base64_encode($message->body)) : rtrim($message->body)). 351 // "\n--".$att_boundary. 352 // "\nContent-Type: {$mess2->headers['content-type']}\n\n". 353 // @imap_body($this->_mbox, $forward, FT_PEEK | FT_UID)."\n\n"; 354 $body = "\n--". 355 $att_boundary. 356 "\nContent-Type: $forward_h_ct\nContent-Transfer-Encoding: $forward_h_cte\n\n". 357 $body; 358 } 359 360 $body .= "--$att_boundary--\n\n"; 361 } 362 363 unset($mobj2); 364 } 365 366 // unset origmail - free memory 367 unset($origmail); 368 369 } 370 371 // remove carriage-returns from body 372 $body = str_replace("\r\n", "\n", $body); 373 374 if (!$multipartmixed) { 375 if (!empty($forward_h_ct)) $headers .= "\nContent-Type: $forward_h_ct"; 376 if (!empty($forward_h_cte)) $headers .= "\nContent-Transfer-Encoding: $forward_h_cte"; 377 } 378 //advanced debugging 379 debugLog("IMAP-SendMail: parsed message: ". print_r($message,1)); 380 debugLog("IMAP-SendMail: headers: $headers"); 381 debugLog("IMAP-SendMail: subject: {$message->headers["subject"]}"); 382 debugLog("IMAP-SendMail: body: $body"); 383 384 if (!defined('IMAP_USE_IMAPMAIL') || IMAP_USE_IMAPMAIL == true) { 385 $send = @imap_mail ( $toaddr, $message->headers["subject"], $body, $headers, $ccaddr, $bccaddr); 386 } 387 else { 388 if (!empty($ccaddr)) $headers .= "\nCc: $ccaddr"; 389 if (!empty($bccaddr)) $headers .= "\nBcc: $bccaddr"; 390 $send = @mail ( $toaddr, $message->headers["subject"], $body, $headers, $envelopefrom ); 391 } 392 393 // email sent? 394 if (!$send) { 395 debugLog("The email could not be sent. Last-IMAP-error: ". imap_last_error()); 396 } 397 398 // add message to the sent folder 399 // build complete headers 400 $headers .= "\nTo: $toaddr"; 401 $headers .= "\nSubject: " . $message->headers["subject"]; 402 403 if (!defined('IMAP_USE_IMAPMAIL') || IMAP_USE_IMAPMAIL == true) { 404 if (!empty($ccaddr)) $headers .= "\nCc: $ccaddr"; 405 if (!empty($bccaddr)) $headers .= "\nBcc: $bccaddr"; 406 } 407 debugLog("IMAP-SendMail: complete headers: $headers"); 408 409 $asf = false; 410 if ($this->_sentID) { 411 $asf = $this->addSentMessage($this->_sentID, $headers, $body); 412 } 413 else if(defined("IMAP_SENTFOLDER")) { 414 $asf = $this->addSentMessage(IMAP_SENTFOLDER, $headers, $body); 415 debugLog("IMAP-SendMail: Outgoing mail saved in configured 'Sent' folder '".IMAP_SENTFOLDER."': ". (($asf)?"success":"failed")); 416 } 417 // No Sent folder set, try defaults 418 else { 419 debugLog("IMAP-SendMail: No Sent mailbox set"); 420 if($this->addSentMessage("INBOX.Sent", $headers, $body)) { 421 debugLog("IMAP-SendMail: Outgoing mail saved in 'INBOX.Sent'"); 422 $asf = true; 423 } 424 else if ($this->addSentMessage("Sent", $headers, $body)) { 425 debugLog("IMAP-SendMail: Outgoing mail saved in 'Sent'"); 426 $asf = true; 427 } 428 else if ($this->addSentMessage("Sent Items", $headers, $body)) { 429 debugLog("IMAP-SendMail: Outgoing mail saved in 'Sent Items'"); 430 $asf = true; 431 } 432 } 433 434 // unset mimedecoder - free memory 435 unset($mobj); 436 return ($send && $asf); 437 } 438 438 439 439 /* Should return a wastebasket folder if there is one. This is used when deleting … … 468 468 if ($search !== false) 469 469 $sequence = implode(",", $search); 470 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> A fun ção @imap_search leu as seguintes SEQUÊNCIAS do servidor IMAP com base no filtro de data: '.$sequence);470 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> A função @imap_search leu as seguintes SEQUÃNCIAS do servidor IMAP com base no filtro de data: '.$sequence); 471 471 } 472 472 … … 479 479 $date = ""; 480 480 $vars = get_object_vars($overview); 481 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> A fun ção @imap_fetch_overview leu mais detalhes da mensagem: '. print_r($overview,1));481 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> A função @imap_fetch_overview leu mais detalhes da mensagem: '. print_r($overview,1)); 482 482 if (array_key_exists( "date", $vars)) { 483 483 // message is out of range for cutoffdate, ignore it 484 484 if(strtotime(preg_replace("/\(.*\)/", "", $overview->date)) < $cutoffdate) { // emerson-faria.nobre@serpro.gov.br - 07/feb/2011 485 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> O overview->date: '.$overview->date.' (overview->date_timestamp: '.strtotime(preg_replace("/\(.*\)/", "", $overview->date)).') é menor que o $cutoffdate: '.date("d/m/Y G:i:s",$cutoffdate).' ($cutoffdate_timestamp: '.$cutoffdate.') ou a função "strtotime" gerou um ERRO porque não conseguiu retornar um valor para o overview->date_timestamp. A mensagem será descartada da sincronização.');485 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> O overview->date: '.$overview->date.' (overview->date_timestamp: '.strtotime(preg_replace("/\(.*\)/", "", $overview->date)).') é menor que o $cutoffdate: '.date("d/m/Y G:i:s",$cutoffdate).' ($cutoffdate_timestamp: '.$cutoffdate.') ou a função "strtotime" gerou um ERRO porque não conseguiu retornar um valor para o overview->date_timestamp. A mensagem será descartada da sincronização.'); 486 486 continue; 487 487 } 488 488 //if(strtotime($overview->date) < $cutoffdate) continue; 489 489 $date = $overview->date; 490 } else if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> ERRO: O campo date n ão existe no overview da mensagem.');490 } else if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> ERRO: O campo date não existe no overview da mensagem.'); 491 491 492 492 // cut of deleted messages 493 493 if (array_key_exists( "deleted", $vars) && $overview->deleted) { 494 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> A mensagem est á com o flag deleted ativo e será descartada da sincronização');495 494 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> A mensagem está com o flag deleted ativo e será descartada da sincronização'); 495 continue; 496 496 } 497 497 … … 506 506 $message["flags"] = 1; 507 507 array_push($messages, $message); 508 } else if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> ERRO: O campo uid n ão existe no overview da mensagem.');509 }510 }508 } else if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetMessageList-> ERRO: O campo uid não existe no overview da mensagem.'); 509 } 510 } 511 511 return $messages; 512 512 } … … 523 523 $list = array_reverse($list); 524 524 foreach ($list as $val) { 525 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetFolderList-> Pasta lida usando a fun ção @imap_getmailboxes: '.print_r($val,1));525 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetFolderList-> Pasta lida usando a função @imap_getmailboxes: '.print_r($val,1)); 526 526 $box = array(); 527 527 … … 542 542 $box["parent"] = "0"; 543 543 } 544 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetFolderList-> Par âmetros da pasta após decodificação: '.print_r($box,1));544 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog('IMAP::GetFolderList-> Parâmetros da pasta após decodificação: '.print_r($box,1)); 545 545 $folders[]=$box; 546 546 } … … 699 699 if (isset($message->parts[$part]->body)) 700 700 print $message->parts[$part]->body; 701 701 702 702 // unset mimedecoder & mail 703 703 unset($mobj); … … 729 729 $vars = get_object_vars($overview[0]); 730 730 731 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL') and (! array_key_exists( "uid", $vars))) debugLog('IMAP::StatMessage-> ERRO: A mensagem ser á desconsiderada porque não tem o campo "uid"');731 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL') and (! array_key_exists( "uid", $vars))) debugLog('IMAP::StatMessage-> ERRO: A mensagem será desconsiderada porque não tem o campo "uid"'); 732 732 // without uid it's not a valid message 733 733 if (! array_key_exists( "uid", $vars)) return false; … … 768 768 $mail = @imap_fetchheader($this->_mbox, $id, FT_PREFETCHTEXT | FT_UID) . @imap_body($this->_mbox, $id, FT_PEEK | FT_UID); 769 769 770 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog("IMAP-GetMessage: Mensagem lida do servidor IMAP atrav és da função @imap_fetchheader: ". print_r($mail,1));770 if (TRACE_UID !== false and (TRACE_TYPE == 'IMAP' or TRACE_TYPE == 'ALL')) traceLog("IMAP-GetMessage: Mensagem lida do servidor IMAP através da função @imap_fetchheader: ". print_r($mail,1)); 771 771 772 772 $mobj = new Mail_mimeDecode($mail); … … 999 999 // Remove the HTML tags using the 'html2text' - emerson-faria.nobre@serpro.gov.br 1000 1000 // The 'html2text' (http://www.mbayer.de/html2text) must be installed in Z-Push server. 1001 1001 1002 1002 // Advanced debug 1003 1003 // debugLog("IMAP-getBody: subject: " . $message->headers["subject"]); 1004 $body = utf8_encode($body); 1004 $body = utf8_encode($body); 1005 1005 libxml_use_internal_errors(true); 1006 1006 try { … … 1054 1054 1055 1055 if(strcasecmp($message->ctype_primary,"multipart")==0 && isset($message->parts) && is_array($message->parts)) { 1056 foreach($message->parts as $part) {1056 foreach($message->parts as $part) { 1057 1057 if(!isset($part->disposition) || strcasecmp($part->disposition,"attachment")) { 1058 1058 $this->getBodyRecursive($part, $subtype, $body); … … 1086 1086 1087 1087 // build a multipart email, embedding body and one file (for attachments) 1088 function mail_attach($filenm,$filesize,$file_cont,$body, $body_ct, $body_cte, $boundary = false) { 1089 if (!$boundary) $boundary = strtoupper(md5(uniqid(time()))); 1090 1091 //remove the ending boundary because we will add it at the end 1092 $body = str_replace("--$boundary--", "", $body); 1093 1094 $mail_header = "Content-Type: multipart/mixed; boundary=$boundary\n"; 1095 1096 // build main body with the sumitted type & encoding from the pda 1097 $mail_body = $this->enc_multipart($boundary, $body, $body_ct, $body_cte); 1098 $mail_body .= $this->enc_attach_file($boundary, $filenm, $filesize, $file_cont); 1099 1100 $mail_body .= "--$boundary--\n\n"; 1101 return array($mail_header, $mail_body); 1102 } 1103 1104 function enc_multipart($boundary, $body, $body_ct, $body_cte) { 1088 function mail_attach($filenm,$filesize,$file_cont,$body, $body_ct, $body_cte, $boundary = false) { 1089 if (!$boundary) $boundary = strtoupper(md5(uniqid(time()))); 1090 1091 //remove the ending boundary because we will add it at the end 1092 $body = str_replace("--$boundary--", "", $body); 1093 1094 $mail_header = "Content-Type: multipart/mixed; boundary=$boundary\n"; 1095 1096 // build main body with the sumitted type & encoding from the pda 1097 $mail_body = $this->enc_multipart($boundary, $body, $body_ct, $body_cte); 1098 $mail_body .= $this->enc_attach_file($boundary, $filenm, $filesize, $file_cont); 1099 1100 $mail_body .= "--$boundary--\n\n"; 1101 1102 return array($mail_header, $mail_body); 1103 } 1104 1105 function enc_multipart($boundary, $body, $body_ct, $body_cte) { 1105 1106 // $mail_body = "This is a multi-part message in MIME format\n\n"; 1106 1107 // $mail_body .= "--$boundary\n"; 1107 1108 // $mail_body .= "Content-Type: $body_ct\n"; 1108 1109 // $mail_body .= "Content-Transfer-Encoding: $body_cte\n\n"; 1109 1110 1111 1112 1110 $mail_body = "$body\n\n"; 1111 1112 return $mail_body; 1113 } 1113 1114 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1115 function enc_attach_file($boundary, $filenm, $filesize, $file_cont, $content_type = "") { 1116 if (!$content_type) $content_type = "text/plain"; 1117 $mail_body = "--$boundary\n"; 1118 $mail_body .= "Content-Type: $content_type; name=\"$filenm\"\n"; 1119 $mail_body .= "Content-Transfer-Encoding: base64\n"; 1120 $mail_body .= "Content-Disposition: attachment; filename=\"$filenm\"\n"; 1121 $mail_body .= "Content-Description: $filenm\n\n"; 1122 //contrib - chunk base64 encoded attachments 1123 $mail_body .= chunk_split(base64_encode($file_cont)) . "\n\n"; 1124 1125 return $mail_body; 1126 } 1127 1127 1128 // adds a message as seen to a specified folder (used for saving sent mails) 1128 1129 function addSentMessage($folderid, $header, $body) { -
contrib/z-push/include/mimeDecode.php
r4613 r4898 102 102 class Mail_mimeDecode 103 103 { 104 /** 105 * The raw email to decode 106 * 107 * @var string 108 * @access private 109 */ 110 var $_input; 111 112 /** 113 * The header part of the input 114 * 115 * @var string 116 * @access private 117 */ 118 var $_header; 119 120 /** 121 * The body part of the input 122 * 123 * @var string 124 * @access private 125 */ 126 var $_body; 127 128 /** 129 * If an error occurs, this is used to store the message 130 * 131 * @var string 132 * @access private 133 */ 134 var $_error; 135 136 /** 137 * Flag to determine whether to include bodies in the 138 * returned object. 139 * 140 * @var boolean 141 * @access private 142 */ 143 var $_include_bodies; 144 145 /** 146 * Flag to determine whether to decode bodies 147 * 148 * @var boolean 149 * @access private 150 */ 151 var $_decode_bodies; 152 153 /** 154 * Flag to determine whether to decode headers 155 * 156 * @var boolean 157 * @access private 158 */ 159 var $_decode_headers; 160 161 /** 162 * Flag to determine whether to include attached messages 163 * as body in the returned object. Depends on $_include_bodies 164 * 165 * @var boolean 166 * @access private 167 */ 168 var $_rfc822_bodies; 169 170 /** 171 * Constructor. 172 * 173 * Sets up the object, initialise the variables, and splits and 174 * stores the header and body of the input. 175 * 176 * @param string The input to decode 177 * @access public 178 */ 179 function Mail_mimeDecode($input, $deprecated_linefeed = '') 180 { 181 list($header, $body) = $this->_splitBodyHeader($input); 182 183 $this->_input = $input; 184 $this->_header = $header; 185 $this->_body = $body; 186 $this->_decode_bodies = false; 187 $this->_include_bodies = true; 188 $this->_rfc822_bodies = false; 189 } 190 191 /** 192 * Begins the decoding process. If called statically 193 * it will create an object and call the decode() method 194 * of it. 195 * 196 * @param array An array of various parameters that determine 197 * various things: 198 * include_bodies - Whether to include the body in the returned 199 * object. 200 * decode_bodies - Whether to decode the bodies 201 * of the parts. (Transfer encoding) 202 * decode_headers - Whether to decode headers 203 * input - If called statically, this will be treated 204 * as the input 205 * charset - convert all data to this charset 206 * @return object Decoded results 207 * @access public 208 */ 209 function decode($params = null) 210 { 211 // determine if this method has been called statically 212 $isStatic = !(isset($this) && get_class($this) == __CLASS__); 213 214 // Have we been called statically? 215 // If so, create an object and pass details to that. 216 if ($isStatic AND isset($params['input'])) { 217 218 $obj = new Mail_mimeDecode($params['input']); 219 $structure = $obj->decode($params); 220 221 // Called statically but no input 222 } elseif ($isStatic) { 223 return $this->raiseError('Called statically and no input given'); 224 225 // Called via an object 226 } else { 227 $this->_include_bodies = isset($params['include_bodies']) ? 228 $params['include_bodies'] : false; 229 $this->_decode_bodies = isset($params['decode_bodies']) ? 230 $params['decode_bodies'] : false; 231 $this->_decode_headers = isset($params['decode_headers']) ? 232 $params['decode_headers'] : false; 233 $this->_rfc822_bodies = isset($params['rfc_822bodies']) ? 234 $params['rfc_822bodies'] : false; 235 $this->_charset = isset($params['charset']) ? 236 strtolower($params['charset']) : 'utf-8'; 237 238 $structure = $this->_decode($this->_header, $this->_body); 239 if ($structure === false) { 240 $structure = $this->raiseError($this->_error); 241 } 242 } 243 244 return $structure; 245 } 246 247 /** 248 * Performs the decoding. Decodes the body string passed to it 249 * If it finds certain content-types it will call itself in a 250 * recursive fashion 251 * 252 * @param string Header section 253 * @param string Body section 254 * @return object Results of decoding process 255 * @access private 256 */ 257 function _decode($headers, $body, $default_ctype = 'text/plain') 258 { 259 $return = new stdClass; 260 $return->headers = array(); 261 $headers = $this->_parseHeaders($headers); 262 263 foreach ($headers as $value) { 264 if (isset($return->headers[strtolower($value['name'])]) AND !is_array($return->headers[strtolower($value['name'])])) { 265 $return->headers[strtolower($value['name'])] = array($return->headers[strtolower($value['name'])]); 266 $return->headers[strtolower($value['name'])][] = $value['value']; 267 268 } elseif (isset($return->headers[strtolower($value['name'])])) { 269 $return->headers[strtolower($value['name'])][] = $value['value']; 270 271 } else { 272 $return->headers[strtolower($value['name'])] = $value['value']; 273 } 274 } 275 276 reset($headers); 277 while (list($key, $value) = each($headers)) { 278 $headers[$key]['name'] = strtolower($headers[$key]['name']); 279 switch ($headers[$key]['name']) { 280 281 case 'content-type': 282 $content_type = $this->_parseHeaderValue($headers[$key]['value']); 283 284 if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) { 285 $return->ctype_primary = $regs[1]; 286 $return->ctype_secondary = $regs[2]; 287 } 288 289 if (isset($content_type['other'])) { 290 while (list($p_name, $p_value) = each($content_type['other'])) { 291 $return->ctype_parameters[$p_name] = $p_value; 292 } 293 } 294 break; 295 296 case 'content-disposition': 297 $content_disposition = $this->_parseHeaderValue($headers[$key]['value']); 298 $return->disposition = $content_disposition['value']; 299 if (isset($content_disposition['other'])) { 300 while (list($p_name, $p_value) = each($content_disposition['other'])) { 301 $return->d_parameters[$p_name] = $p_value; 302 } 303 } 304 break; 305 306 case 'content-transfer-encoding': 307 $content_transfer_encoding = $this->_parseHeaderValue($headers[$key]['value']); 308 break; 309 } 310 } 311 312 if (isset($content_type)) { 313 switch (strtolower($content_type['value'])) { 314 case 'text/plain': 315 $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit'; 316 $charset = isset($return->ctype_parameters['charset']) ? $return->ctype_parameters['charset'] : $this->_charset; 317 $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding, $charset) : $body) : null; 318 break; 319 320 case 'text/html': 321 $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit'; 322 $charset = isset($return->ctype_parameters['charset']) ? $return->ctype_parameters['charset'] : $this->_charset; 323 $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding, $charset) : $body) : null; 324 break; 325 326 case 'multipart/parallel': 327 case 'multipart/appledouble': // Appledouble mail 328 case 'multipart/report': // RFC1892 329 case 'multipart/signed': // PGP 330 case 'multipart/digest': 331 case 'multipart/alternative': 332 case 'multipart/related': 333 case 'multipart/mixed': 334 if(!isset($content_type['other']['boundary'])){ 335 $this->_error = 'No boundary found for ' . $content_type['value'] . ' part'; 336 return false; 337 } 338 339 $default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain'; 340 341 $parts = $this->_boundarySplit($body, $content_type['other']['boundary']); 342 for ($i = 0; $i < count($parts); $i++) { 343 list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]); 344 $part = $this->_decode($part_header, $part_body, $default_ctype); 345 if($part === false) 346 $part = $this->raiseError($this->_error); 347 $return->parts[] = $part; 348 } 349 break; 350 351 case 'message/rfc822': 352 if ($this->_rfc822_bodies) { 353 $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit'; 354 $charset = isset($return->ctype_parameters['charset']) ? $return->ctype_parameters['charset'] : $this->_charset; 355 $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding, $charset) : $body); 356 } 357 358 $obj = new Mail_mimeDecode($body); 359 $return->parts[] = $obj->decode(array('include_bodies' => $this->_include_bodies, 360 'decode_bodies' => $this->_decode_bodies, 361 'decode_headers' => $this->_decode_headers)); 362 unset($obj); 363 break; 364 365 default: 366 if(!isset($content_transfer_encoding['value'])) 367 $content_transfer_encoding['value'] = '7bit'; 368 // if there is no explicit charset, then don't try to convert to default charset, and make sure that only text mimetypes are converted 369 $charset = (isset($return->ctype_parameters['charset']) && ((isset($return->ctype_primary) && $return->ctype_primary == 'text') || !isset($return->ctype_primary)) )? $return->ctype_parameters['charset']: ''; 370 $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $content_transfer_encoding['value'], $charset) : $body) : null; 371 break; 372 } 373 374 } else { 375 $ctype = explode('/', $default_ctype); 376 $return->ctype_primary = $ctype[0]; 377 $return->ctype_secondary = $ctype[1]; 378 $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body) : $body) : null; 379 } 380 381 return $return; 382 } 383 384 /** 385 * Given the output of the above function, this will return an 386 * array of references to the parts, indexed by mime number. 387 * 388 * @param object $structure The structure to go through 389 * @param string $mime_number Internal use only. 390 * @return array Mime numbers 391 */ 392 function &getMimeNumbers(&$structure, $no_refs = false, $mime_number = '', $prepend = '') 393 { 394 $return = array(); 395 if (!empty($structure->parts)) { 396 if ($mime_number != '') { 397 $structure->mime_id = $prepend . $mime_number; 398 $return[$prepend . $mime_number] = &$structure; 399 } 400 for ($i = 0; $i < count($structure->parts); $i++) { 401 402 403 if (!empty($structure->headers['content-type']) AND substr(strtolower($structure->headers['content-type']), 0, 8) == 'message/') { 404 $prepend = $prepend . $mime_number . '.'; 405 $_mime_number = ''; 406 } else { 407 $_mime_number = ($mime_number == '' ? $i + 1 : sprintf('%s.%s', $mime_number, $i + 1)); 408 } 409 410 $arr = &Mail_mimeDecode::getMimeNumbers($structure->parts[$i], $no_refs, $_mime_number, $prepend); 411 foreach ($arr as $key => $val) { 412 $no_refs ? $return[$key] = '' : $return[$key] = &$arr[$key]; 413 } 414 } 415 } else { 416 if ($mime_number == '') { 417 $mime_number = '1'; 418 } 419 $structure->mime_id = $prepend . $mime_number; 420 $no_refs ? $return[$prepend . $mime_number] = '' : $return[$prepend . $mime_number] = &$structure; 421 } 422 423 return $return; 424 } 425 426 /** 427 * Given a string containing a header and body 428 * section, this function will split them (at the first 429 * blank line) and return them. 430 * 431 * @param string Input to split apart 432 * @return array Contains header and body section 433 * @access private 434 */ 435 function _splitBodyHeader($input) 436 { 437 if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) { 438 return array($match[1], $match[2]); 439 } 440 $this->_error = 'Could not split header and body'; 441 return false; 442 } 443 444 /** 445 * Parse headers given in $input and return 446 * as assoc array. 447 * 448 * @param string Headers to parse 449 * @return array Contains parsed headers 450 * @access private 451 */ 452 function _parseHeaders($input) 453 { 454 455 if ($input !== '') { 456 // Unfold the input 457 $input = preg_replace("/\r?\n/", "\r\n", $input); 458 $input = preg_replace("/\r\n(\t| )+/", ' ', $input); 459 $headers = explode("\r\n", trim($input)); 460 461 foreach ($headers as $value) { 462 $hdr_name = substr($value, 0, $pos = strpos($value, ':')); 463 $hdr_value = substr($value, $pos+1); 464 if($hdr_value[0] == ' ') 465 $hdr_value = substr($hdr_value, 1); 466 467 $return[] = array( 468 'name' => $hdr_name, 469 'value' => $this->_decode_headers ? $this->_decodeHeader($hdr_value) : $hdr_value 470 ); 471 } 472 } else { 473 $return = array(); 474 } 475 476 return $return; 477 } 478 479 /** 480 * Function to parse a header value, 481 * extract first part, and any secondary 482 * parts (after ;) This function is not as 483 * robust as it could be. Eg. header comments 484 * in the wrong place will probably break it. 485 * 486 * @param string Header value to parse 487 * @return array Contains parsed result 488 * @access private 489 */ 490 function _parseHeaderValue($input) 491 { 492 493 if (($pos = strpos($input, ';')) !== false) { 494 495 $return['value'] = trim(substr($input, 0, $pos)); 496 $input = trim(substr($input, $pos+1)); 497 498 if (strlen($input) > 0) { 499 500 // This splits on a semi-colon, if there's no preceeding backslash 501 // Now works with quoted values; had to glue the \; breaks in PHP 502 // the regex is already bordering on incomprehensible 503 //$splitRegex = '/([^;\'"]*[\'"]([^\'"]*([^\'"]*)*)[\'"][^;\'"]*|([^;]+))(;|$)/'; 504 // simplyfied RegEx - Nokia Mail2 sends boundaries containing ' which break the above regex 505 $splitRegex = '/([^;\'"]*[\'"]([^\'"]*)[\'"][^;\'"]*|([^;]+))(;|$)/'; 506 preg_match_all($splitRegex, $input, $matches); 507 508 $parameters = array(); 509 for ($i=0; $i<count($matches[0]); $i++) { 510 $param = $matches[0][$i]; 511 while (substr($param, -2) == '\;') { 512 $param .= $matches[0][++$i]; 513 } 514 $parameters[] = $param; 515 } 516 517 for ($i = 0; $i < count($parameters); $i++) { 518 $param_name = trim(substr($parameters[$i], 0, $pos = strpos($parameters[$i], '=')), "'\";\t\\ "); 519 $param_value = trim(str_replace('\;', ';', substr($parameters[$i], $pos + 1)), "'\";\t\\ "); 520 if (!empty($param_value[0]) && $param_value[0] == '"') { 521 $param_value = substr($param_value, 1, -1); 522 } 523 $return['other'][$param_name] = $param_value; 524 $return['other'][strtolower($param_name)] = $param_value; 525 } 526 } 527 } else { 528 $return['value'] = trim($input); 529 } 530 531 return $return; 532 } 533 534 /** 535 * This function splits the input based 536 * on the given boundary 537 * 538 * @param string Input to parse 539 * @return array Contains array of resulting mime parts 540 * @access private 541 */ 542 function _boundarySplit($input, $boundary) 543 { 544 $parts = array(); 545 546 $bs_possible = substr($boundary, 2, -2); 547 $bs_check = '\"' . $bs_possible . '\"'; 548 549 if ($boundary == $bs_check) { 550 $boundary = $bs_possible; 551 } 552 553 $tmp = explode('--' . $boundary, $input); 554 555 for ($i = 1; $i < count($tmp) - 1; $i++) { 556 $parts[] = $tmp[$i]; 557 } 558 559 return $parts; 560 } 561 562 /** 563 * Given a header, this function will decode it 564 * according to RFC2047. Probably not *exactly* 565 * conformant, but it does pass all the given 566 * examples (in RFC2047). 567 * 568 * @param string Input header value to decode 569 * @return string Decoded header value 570 * @access private 571 */ 572 function _decodeHeader($input) 573 { 574 // Remove white space between encoded-words 575 $input = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $input); 576 577 // For each encoded-word... 578 while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i', $input, $matches)) { 579 580 $encoded = $matches[1]; 581 $charset = $matches[2]; 582 $encoding = $matches[3]; 583 $text = $matches[4]; 584 585 switch (strtolower($encoding)) { 586 case 'b': 587 $text = base64_decode($text); 588 break; 589 590 case 'q': 591 $text = str_replace('_', ' ', $text); 592 preg_match_all('/=([a-f0-9]{2})/i', $text, $matches); 593 foreach($matches[1] as $value) 594 $text = str_replace('='.$value, chr(hexdec($value)), $text); 595 break; 596 } 597 598 $input = str_replace($encoded, $this->_fromCharset($charset, $text), $input); 599 } 600 601 return $input; 602 } 603 604 /** 605 * Given a body string and an encoding type, 606 * this function will decode and return it. 607 * 608 * @param string Input body to decode 609 * @param string Encoding type to use. 610 * @return string Decoded body 611 * @access private 612 */ 613 function _decodeBody($input, $encoding = '7bit', $charset = '') 614 { 615 switch (strtolower($encoding)) { 616 case '7bit': 617 return $this->_fromCharset($charset, $input);; 618 break; 619 620 case '8bit': 621 return $this->_fromCharset($charset, $input); 622 break; 623 624 case 'quoted-printable': 625 return $this->_fromCharset($charset, $this->_quotedPrintableDecode($input)); 626 break; 627 628 case 'base64': 629 return $this->_fromCharset($charset, base64_decode($input)); 630 break; 631 632 default: 633 return $input; 634 } 635 } 636 637 /** 638 * Given a quoted-printable string, this 639 * function will decode and return it. 640 * 641 * @param string Input body to decode 642 * @return string Decoded body 643 * @access private 644 */ 645 function _quotedPrintableDecode($input) 646 { 647 // Remove soft line breaks 648 $input = preg_replace("/=\r?\n/", '', $input); 649 650 // Replace encoded characters 651 $input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input); 652 653 return $input; 654 } 655 656 /** 657 * Checks the input for uuencoded files and returns 658 * an array of them. Can be called statically, eg: 659 * 660 * $files =& Mail_mimeDecode::uudecode($some_text); 661 * 662 * It will check for the begin 666 ... end syntax 663 * however and won't just blindly decode whatever you 664 * pass it. 665 * 666 * @param string Input body to look for attahcments in 667 * @return array Decoded bodies, filenames and permissions 668 * @access public 669 * @author Unknown 670 */ 671 function &uudecode($input) 672 { 673 // Find all uuencoded sections 674 preg_match_all("/begin ([0-7]{3}) (.+)\r?\n(.+)\r?\nend/Us", $input, $matches); 675 676 for ($j = 0; $j < count($matches[3]); $j++) { 677 678 $str = $matches[3][$j]; 679 $filename = $matches[2][$j]; 680 $fileperm = $matches[1][$j]; 681 682 $file = ''; 683 $str = preg_split("/\r?\n/", trim($str)); 684 $strlen = count($str); 685 686 for ($i = 0; $i < $strlen; $i++) { 687 $pos = 1; 688 $d = 0; 689 $len=(int)(((ord(substr($str[$i],0,1)) -32) - ' ') & 077); 690 691 while (($d + 3 <= $len) AND ($pos + 4 <= strlen($str[$i]))) { 692 $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20); 693 $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20); 694 $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20); 695 $c3 = (ord(substr($str[$i],$pos+3,1)) ^ 0x20); 696 $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)); 697 698 $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2)); 699 700 $file .= chr(((($c2 - ' ') & 077) << 6) | (($c3 - ' ') & 077)); 701 702 $pos += 4; 703 $d += 3; 704 } 705 706 if (($d + 2 <= $len) && ($pos + 3 <= strlen($str[$i]))) { 707 $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20); 708 $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20); 709 $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20); 710 $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)); 711 712 $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2)); 713 714 $pos += 3; 715 $d += 2; 716 } 717 718 if (($d + 1 <= $len) && ($pos + 2 <= strlen($str[$i]))) { 719 $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20); 720 $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20); 721 $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)); 722 723 } 724 } 725 $files[] = array('filename' => $filename, 'fileperm' => $fileperm, 'filedata' => $file); 726 } 727 728 return $files; 729 } 730 731 /** 732 * getSendArray() returns the arguments required for Mail::send() 733 * used to build the arguments for a mail::send() call 734 * 735 * Usage: 736 * $mailtext = Full email (for example generated by a template) 737 * $decoder = new Mail_mimeDecode($mailtext); 738 * $parts = $decoder->getSendArray(); 739 * if (!PEAR::isError($parts) { 740 * list($recipents,$headers,$body) = $parts; 741 * $mail = Mail::factory('smtp'); 742 * $mail->send($recipents,$headers,$body); 743 * } else { 744 * echo $parts->message; 745 * } 746 * @return mixed array of recipeint, headers,body or Pear_Error 747 * @access public 748 * @author Alan Knowles <alan@akbkhome.com> 749 */ 750 function getSendArray() 751 { 752 // prevent warning if this is not set 753 $this->_decode_headers = FALSE; 754 $headerlist =$this->_parseHeaders($this->_header); 755 $to = ""; 756 if (!$headerlist) { 757 return $this->raiseError("Message did not contain headers"); 758 } 759 foreach($headerlist as $item) { 760 $header[$item['name']] = $item['value']; 761 switch (strtolower($item['name'])) { 762 case "to": 763 case "cc": 764 case "bcc": 765 $to .= ",".$item['value']; 766 default: 767 break; 768 } 769 } 770 if ($to == "") { 771 return $this->raiseError("Message did not contain any recipents"); 772 } 773 $to = substr($to,1); 774 return array($to,$header,$this->_body); 775 } 776 777 /** 778 * Returns a xml copy of the output of 779 * Mail_mimeDecode::decode. Pass the output in as the 780 * argument. This function can be called statically. Eg: 781 * 782 * $output = $obj->decode(); 783 * $xml = Mail_mimeDecode::getXML($output); 784 * 785 * The DTD used for this should have been in the package. Or 786 * alternatively you can get it from cvs, or here: 787 * http://www.phpguru.org/xmail/xmail.dtd. 788 * 789 * @param object Input to convert to xml. This should be the 790 * output of the Mail_mimeDecode::decode function 791 * @return string XML version of input 792 * @access public 793 */ 794 function getXML($input) 795 { 796 $crlf = "\r\n"; 797 $output = '<?xml version=\'1.0\'?>' . $crlf . 104 /** 105 * The raw email to decode 106 * 107 * @var string 108 * @access private 109 */ 110 var $_input; 111 112 /** 113 * The header part of the input 114 * 115 * @var string 116 * @access private 117 */ 118 var $_header; 119 120 /** 121 * The body part of the input 122 * 123 * @var string 124 * @access private 125 */ 126 var $_body; 127 128 /** 129 * If an error occurs, this is used to store the message 130 * 131 * @var string 132 * @access private 133 */ 134 var $_error; 135 136 /** 137 * Flag to determine whether to include bodies in the 138 * returned object. 139 * 140 * @var boolean 141 * @access private 142 */ 143 var $_include_bodies; 144 145 /** 146 * Flag to determine whether to decode bodies 147 * 148 * @var boolean 149 * @access private 150 */ 151 var $_decode_bodies; 152 153 /** 154 * Flag to determine whether to decode headers 155 * 156 * @var boolean 157 * @access private 158 */ 159 var $_decode_headers; 160 161 /** 162 * Flag to determine whether to include attached messages 163 * as body in the returned object. Depends on $_include_bodies 164 * 165 * @var boolean 166 * @access private 167 */ 168 var $_rfc822_bodies; 169 170 /** 171 * Constructor. 172 * 173 * Sets up the object, initialise the variables, and splits and 174 * stores the header and body of the input. 175 * 176 * @param string The input to decode 177 * @access public 178 */ 179 function Mail_mimeDecode($input, $deprecated_linefeed = '') 180 { 181 list($header, $body) = $this->_splitBodyHeader($input); 182 183 $this->_input = $input; 184 $this->_header = $header; 185 $this->_body = $body; 186 $this->_decode_bodies = false; 187 $this->_include_bodies = true; 188 $this->_rfc822_bodies = false; 189 } 190 191 /** 192 * Begins the decoding process. If called statically 193 * it will create an object and call the decode() method 194 * of it. 195 * 196 * @param array An array of various parameters that determine 197 * various things: 198 * include_bodies - Whether to include the body in the returned 199 * object. 200 * decode_bodies - Whether to decode the bodies 201 * of the parts. (Transfer encoding) 202 * decode_headers - Whether to decode headers 203 * input - If called statically, this will be treated 204 * as the input 205 * charset - convert all data to this charset 206 * @return object Decoded results 207 * @access public 208 */ 209 function decode($params = null) 210 { 211 // determine if this method has been called statically 212 $isStatic = !(isset($this) && get_class($this) == __CLASS__); 213 214 // Have we been called statically? 215 // If so, create an object and pass details to that. 216 if ($isStatic AND isset($params['input'])) { 217 218 $obj = new Mail_mimeDecode($params['input']); 219 $structure = $obj->decode($params); 220 221 // Called statically but no input 222 } elseif ($isStatic) { 223 return $this->raiseError('Called statically and no input given'); 224 225 // Called via an object 226 } else { 227 $this->_include_bodies = isset($params['include_bodies']) ? 228 $params['include_bodies'] : false; 229 $this->_decode_bodies = isset($params['decode_bodies']) ? 230 $params['decode_bodies'] : false; 231 $this->_decode_headers = isset($params['decode_headers']) ? 232 $params['decode_headers'] : false; 233 $this->_rfc822_bodies = isset($params['rfc_822bodies']) ? 234 $params['rfc_822bodies'] : false; 235 $this->_charset = isset($params['charset']) ? 236 strtolower($params['charset']) : 'utf-8'; 237 238 $structure = $this->_decode($this->_header, $this->_body); 239 if ($structure === false) { 240 $structure = $this->raiseError($this->_error); 241 } 242 } 243 244 return $structure; 245 } 246 247 /** 248 * Performs the decoding. Decodes the body string passed to it 249 * If it finds certain content-types it will call itself in a 250 * recursive fashion 251 * 252 * @param string Header section 253 * @param string Body section 254 * @return object Results of decoding process 255 * @access private 256 */ 257 function _decode($headers, $body, $default_ctype = 'text/plain') 258 { 259 $return = new stdClass; 260 $return->headers = array(); 261 $headers = $this->_parseHeaders($headers); 262 263 foreach ($headers as $value) { 264 if (isset($return->headers[strtolower($value['name'])]) AND !is_array($return->headers[strtolower($value['name'])])) { 265 $return->headers[strtolower($value['name'])] = array($return->headers[strtolower($value['name'])]); 266 $return->headers[strtolower($value['name'])][] = $value['value']; 267 268 } elseif (isset($return->headers[strtolower($value['name'])])) { 269 $return->headers[strtolower($value['name'])][] = $value['value']; 270 271 } else { 272 $return->headers[strtolower($value['name'])] = $value['value']; 273 } 274 } 275 276 reset($headers); 277 while (list($key, $value) = each($headers)) { 278 $headers[$key]['name'] = strtolower($headers[$key]['name']); 279 switch ($headers[$key]['name']) { 280 281 case 'content-type': 282 $content_type = $this->_parseHeaderValue($headers[$key]['value']); 283 284 if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) { 285 $return->ctype_primary = $regs[1]; 286 $return->ctype_secondary = $regs[2]; 287 } 288 289 if (isset($content_type['other'])) { 290 while (list($p_name, $p_value) = each($content_type['other'])) { 291 $return->ctype_parameters[$p_name] = $p_value; 292 } 293 } 294 break; 295 296 case 'content-disposition': 297 $content_disposition = $this->_parseHeaderValue($headers[$key]['value']); 298 $return->disposition = $content_disposition['value']; 299 if (isset($content_disposition['other'])) { 300 while (list($p_name, $p_value) = each($content_disposition['other'])) { 301 $return->d_parameters[$p_name] = $p_value; 302 } 303 } 304 break; 305 306 case 'content-transfer-encoding': 307 $content_transfer_encoding = $this->_parseHeaderValue($headers[$key]['value']); 308 break; 309 } 310 } 311 312 if (isset($content_type)) { 313 switch (strtolower($content_type['value'])) { 314 case 'text/plain': 315 $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit'; 316 $charset = isset($return->ctype_parameters['charset']) ? $return->ctype_parameters['charset'] : $this->_charset; 317 $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding, $charset) : $body) : null; 318 break; 319 320 case 'text/html': 321 $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit'; 322 $charset = isset($return->ctype_parameters['charset']) ? $return->ctype_parameters['charset'] : $this->_charset; 323 $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding, $charset) : $body) : null; 324 break; 325 326 case 'multipart/parallel': 327 case 'multipart/appledouble': // Appledouble mail 328 case 'multipart/report': // RFC1892 329 case 'multipart/signed': // PGP 330 case 'multipart/digest': 331 case 'multipart/alternative': 332 case 'multipart/related': 333 case 'multipart/mixed': 334 if(!isset($content_type['other']['boundary'])){ 335 $this->_error = 'No boundary found for ' . $content_type['value'] . ' part'; 336 return false; 337 } 338 339 $default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain'; 340 341 $parts = $this->_boundarySplit($body, $content_type['other']['boundary']); 342 for ($i = 0; $i < count($parts); $i++) { 343 list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]); 344 $part = $this->_decode($part_header, $part_body, $default_ctype); 345 if($part === false) 346 $part = $this->raiseError($this->_error); 347 $return->parts[] = $part; 348 } 349 break; 350 351 case 'message/rfc822': 352 if ($this->_rfc822_bodies) { 353 $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit'; 354 $charset = isset($return->ctype_parameters['charset']) ? $return->ctype_parameters['charset'] : $this->_charset; 355 $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding, $charset) : $body); 356 } 357 358 $obj = new Mail_mimeDecode($body); 359 $return->parts[] = $obj->decode(array('include_bodies' => $this->_include_bodies, 360 'decode_bodies' => $this->_decode_bodies, 361 'decode_headers' => $this->_decode_headers)); 362 unset($obj); 363 break; 364 365 default: 366 if(!isset($content_transfer_encoding['value'])) 367 $content_transfer_encoding['value'] = '7bit'; 368 369 // if there is no explicit charset, then don't try to convert to default charset, and make sure that only text mimetypes are converted 370 $charset = (isset($return->ctype_parameters['charset']) && ((isset($return->ctype_primary) && $return->ctype_primary == 'text') || !isset($return->ctype_primary)) ) ? $return->ctype_parameters['charset']: ''; 371 $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $content_transfer_encoding['value'], $charset) : $body) : null; 372 break; 373 } 374 375 } else { 376 $ctype = explode('/', $default_ctype); 377 $return->ctype_primary = $ctype[0]; 378 $return->ctype_secondary = $ctype[1]; 379 $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body) : $body) : null; 380 } 381 382 return $return; 383 } 384 385 /** 386 * Given the output of the above function, this will return an 387 * array of references to the parts, indexed by mime number. 388 * 389 * @param object $structure The structure to go through 390 * @param string $mime_number Internal use only. 391 * @return array Mime numbers 392 */ 393 function &getMimeNumbers(&$structure, $no_refs = false, $mime_number = '', $prepend = '') 394 { 395 $return = array(); 396 if (!empty($structure->parts)) { 397 if ($mime_number != '') { 398 $structure->mime_id = $prepend . $mime_number; 399 $return[$prepend . $mime_number] = &$structure; 400 } 401 for ($i = 0; $i < count($structure->parts); $i++) { 402 if (!empty($structure->headers['content-type']) AND substr(strtolower($structure->headers['content-type']), 0, 8) == 'message/') { 403 $prepend = $prepend . $mime_number . '.'; 404 $_mime_number = ''; 405 } else { 406 $_mime_number = ($mime_number == '' ? $i + 1 : sprintf('%s.%s', $mime_number, $i + 1)); 407 } 408 409 $arr = &Mail_mimeDecode::getMimeNumbers($structure->parts[$i], $no_refs, $_mime_number, $prepend); 410 foreach ($arr as $key => $val) { 411 $no_refs ? $return[$key] = '' : $return[$key] = &$arr[$key]; 412 } 413 } 414 } else { 415 if ($mime_number == '') { 416 $mime_number = '1'; 417 } 418 $structure->mime_id = $prepend . $mime_number; 419 $no_refs ? $return[$prepend . $mime_number] = '' : $return[$prepend . $mime_number] = &$structure; 420 } 421 422 return $return; 423 } 424 425 /** 426 * Given a string containing a header and body 427 * section, this function will split them (at the first 428 * blank line) and return them. 429 * 430 * @param string Input to split apart 431 * @return array Contains header and body section 432 * @access private 433 */ 434 function _splitBodyHeader($input) 435 { 436 if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) { 437 return array($match[1], $match[2]); 438 } 439 $this->_error = 'Could not split header and body'; 440 return false; 441 } 442 443 /** 444 * Parse headers given in $input and return 445 * as assoc array. 446 * 447 * @param string Headers to parse 448 * @return array Contains parsed headers 449 * @access private 450 */ 451 function _parseHeaders($input) 452 { 453 454 if ($input !== '') { 455 // Unfold the input 456 $input = preg_replace("/\r?\n/", "\r\n", $input); 457 $input = preg_replace("/\r\n(\t| )+/", ' ', $input); 458 $headers = explode("\r\n", trim($input)); 459 460 foreach ($headers as $value) { 461 $hdr_name = substr($value, 0, $pos = strpos($value, ':')); 462 $hdr_value = substr($value, $pos+1); 463 if($hdr_value[0] == ' ') 464 $hdr_value = substr($hdr_value, 1); 465 466 $return[] = array( 467 'name' => $hdr_name, 468 'value' => $this->_decode_headers ? $this->_decodeHeader($hdr_value) : $hdr_value 469 ); 470 } 471 } else { 472 $return = array(); 473 } 474 475 return $return; 476 } 477 478 /** 479 * Function to parse a header value, 480 * extract first part, and any secondary 481 * parts (after ;) This function is not as 482 * robust as it could be. Eg. header comments 483 * in the wrong place will probably break it. 484 * 485 * @param string Header value to parse 486 * @return array Contains parsed result 487 * @access private 488 */ 489 function _parseHeaderValue($input) 490 { 491 if (($pos = strpos($input, ';')) !== false) { 492 $return['value'] = trim(substr($input, 0, $pos)); 493 $input = trim(substr($input, $pos+1)); 494 495 if (strlen($input) > 0) { 496 // This splits on a semi-colon, if there's no preceeding backslash 497 // Now works with quoted values; had to glue the \; breaks in PHP 498 // the regex is already bordering on incomprehensible 499 //$splitRegex = '/([^;\'"]*[\'"]([^\'"]*([^\'"]*)*)[\'"][^;\'"]*|([^;]+))(;|$)/'; 500 // simplyfied RegEx - Nokia Mail2 sends boundaries containing ' which break the above regex 501 $splitRegex = '/([^;\'"]*[\'"]([^\'"]*)[\'"][^;\'"]*|([^;]+))(;|$)/'; 502 preg_match_all($splitRegex, $input, $matches); 503 504 $parameters = array(); 505 for ($i=0; $i<count($matches[0]); $i++) { 506 $param = $matches[0][$i]; 507 while (substr($param, -2) == '\;') { 508 $param .= $matches[0][++$i]; 509 } 510 $parameters[] = $param; 511 } 512 513 for ($i = 0; $i < count($parameters); $i++) { 514 $param_name = trim(substr($parameters[$i], 0, $pos = strpos($parameters[$i], '=')), "'\";\t\\ "); 515 $param_value = trim(str_replace('\;', ';', substr($parameters[$i], $pos + 1)), "'\";\t\\ "); 516 if (!empty($param_value[0]) && $param_value[0] == '"') { 517 $param_value = substr($param_value, 1, -1); 518 } 519 $return['other'][$param_name] = $param_value; 520 $return['other'][strtolower($param_name)] = $param_value; 521 } 522 } 523 } else { 524 $return['value'] = trim($input); 525 } 526 527 return $return; 528 } 529 530 /** 531 * This function splits the input based 532 * on the given boundary 533 * 534 * @param string Input to parse 535 * @return array Contains array of resulting mime parts 536 * @access private 537 */ 538 function _boundarySplit($input, $boundary) 539 { 540 $parts = array(); 541 542 $bs_possible = substr($boundary, 2, -2); 543 $bs_check = '\"' . $bs_possible . '\"'; 544 545 if ($boundary == $bs_check) { 546 $boundary = $bs_possible; 547 } 548 549 $tmp = explode('--' . $boundary, $input); 550 551 for ($i = 1; $i < count($tmp) - 1; $i++) { 552 $parts[] = $tmp[$i]; 553 } 554 555 return $parts; 556 } 557 558 /** 559 * Given a header, this function will decode it 560 * according to RFC2047. Probably not *exactly* 561 * conformant, but it does pass all the given 562 * examples (in RFC2047). 563 * 564 * @param string Input header value to decode 565 * @return string Decoded header value 566 * @access private 567 */ 568 function _decodeHeader($input) 569 { 570 // Remove white space between encoded-words 571 $input = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $input); 572 573 // For each encoded-word... 574 while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i', $input, $matches)) { 575 $encoded = $matches[1]; 576 $charset = $matches[2]; 577 $encoding = $matches[3]; 578 $text = $matches[4]; 579 580 switch (strtolower($encoding)) { 581 case 'b': 582 $text = base64_decode($text); 583 break; 584 585 case 'q': 586 $text = str_replace('_', ' ', $text); 587 preg_match_all('/=([a-f0-9]{2})/i', $text, $matches); 588 foreach($matches[1] as $value) 589 $text = str_replace('='.$value, chr(hexdec($value)), $text); 590 break; 591 } 592 593 $input = str_replace($encoded, $this->_fromCharset($charset, $text), $input); 594 } 595 596 return $input; 597 } 598 599 /** 600 * Given a body string and an encoding type, 601 * this function will decode and return it. 602 * 603 * @param string Input body to decode 604 * @param string Encoding type to use. 605 * @return string Decoded body 606 * @access private 607 */ 608 function _decodeBody($input, $encoding = '7bit', $charset = '') 609 { 610 switch (strtolower($encoding)) { 611 case '7bit': 612 return $this->_fromCharset($charset, $input);; 613 break; 614 615 case '8bit': 616 return $this->_fromCharset($charset, $input); 617 break; 618 619 case 'quoted-printable': 620 return $this->_fromCharset($charset, $this->_quotedPrintableDecode($input)); 621 break; 622 623 case 'base64': 624 return $this->_fromCharset($charset, base64_decode($input)); 625 break; 626 627 default: 628 return $input; 629 } 630 } 631 632 /** 633 * Given a quoted-printable string, this 634 * function will decode and return it. 635 * 636 * @param string Input body to decode 637 * @return string Decoded body 638 * @access private 639 */ 640 function _quotedPrintableDecode($input) 641 { 642 // Remove soft line breaks 643 $input = preg_replace("/=\r?\n/", '', $input); 644 645 // Replace encoded characters 646 $input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input); 647 648 return $input; 649 } 650 651 /** 652 * Checks the input for uuencoded files and returns 653 * an array of them. Can be called statically, eg: 654 * 655 * $files =& Mail_mimeDecode::uudecode($some_text); 656 * 657 * It will check for the begin 666 ... end syntax 658 * however and won't just blindly decode whatever you 659 * pass it. 660 * 661 * @param string Input body to look for attahcments in 662 * @return array Decoded bodies, filenames and permissions 663 * @access public 664 * @author Unknown 665 */ 666 function &uudecode($input) 667 { 668 // Find all uuencoded sections 669 preg_match_all("/begin ([0-7]{3}) (.+)\r?\n(.+)\r?\nend/Us", $input, $matches); 670 671 for ($j = 0; $j < count($matches[3]); $j++) { 672 $str = $matches[3][$j]; 673 $filename = $matches[2][$j]; 674 $fileperm = $matches[1][$j]; 675 676 $file = ''; 677 $str = preg_split("/\r?\n/", trim($str)); 678 $strlen = count($str); 679 680 for ($i = 0; $i < $strlen; $i++) { 681 $pos = 1; 682 $d = 0; 683 $len=(int)(((ord(substr($str[$i],0,1)) -32) - ' ') & 077); 684 685 while (($d + 3 <= $len) AND ($pos + 4 <= strlen($str[$i]))) { 686 $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20); 687 $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20); 688 $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20); 689 $c3 = (ord(substr($str[$i],$pos+3,1)) ^ 0x20); 690 $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)); 691 692 $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2)); 693 694 $file .= chr(((($c2 - ' ') & 077) << 6) | (($c3 - ' ') & 077)); 695 696 $pos += 4; 697 $d += 3; 698 } 699 700 if (($d + 2 <= $len) && ($pos + 3 <= strlen($str[$i]))) { 701 $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20); 702 $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20); 703 $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20); 704 $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)); 705 706 $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2)); 707 708 $pos += 3; 709 $d += 2; 710 } 711 712 if (($d + 1 <= $len) && ($pos + 2 <= strlen($str[$i]))) { 713 $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20); 714 $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20); 715 $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)); 716 } 717 } 718 $files[] = array('filename' => $filename, 'fileperm' => $fileperm, 'filedata' => $file); 719 } 720 721 return $files; 722 } 723 724 /** 725 * getSendArray() returns the arguments required for Mail::send() 726 * used to build the arguments for a mail::send() call 727 * 728 * Usage: 729 * $mailtext = Full email (for example generated by a template) 730 * $decoder = new Mail_mimeDecode($mailtext); 731 * $parts = $decoder->getSendArray(); 732 * if (!PEAR::isError($parts) { 733 * list($recipents,$headers,$body) = $parts; 734 * $mail = Mail::factory('smtp'); 735 * $mail->send($recipents,$headers,$body); 736 * } else { 737 * echo $parts->message; 738 * } 739 * @return mixed array of recipeint, headers,body or Pear_Error 740 * @access public 741 * @author Alan Knowles <alan@akbkhome.com> 742 */ 743 function getSendArray() 744 { 745 // prevent warning if this is not set 746 $this->_decode_headers = FALSE; 747 $headerlist =$this->_parseHeaders($this->_header); 748 $to = ""; 749 if (!$headerlist) { 750 return $this->raiseError("Message did not contain headers"); 751 } 752 foreach($headerlist as $item) { 753 $header[$item['name']] = $item['value']; 754 switch (strtolower($item['name'])) { 755 case "to": 756 case "cc": 757 case "bcc": 758 $to .= ",".$item['value']; 759 default: 760 break; 761 } 762 } 763 if ($to == "") { 764 return $this->raiseError("Message did not contain any recipents"); 765 } 766 $to = substr($to,1); 767 return array($to,$header,$this->_body); 768 } 769 770 /** 771 * Returns a xml copy of the output of 772 * Mail_mimeDecode::decode. Pass the output in as the 773 * argument. This function can be called statically. Eg: 774 * 775 * $output = $obj->decode(); 776 * $xml = Mail_mimeDecode::getXML($output); 777 * 778 * The DTD used for this should have been in the package. Or 779 * alternatively you can get it from cvs, or here: 780 * http://www.phpguru.org/xmail/xmail.dtd. 781 * 782 * @param object Input to convert to xml. This should be the 783 * output of the Mail_mimeDecode::decode function 784 * @return string XML version of input 785 * @access public 786 */ 787 function getXML($input) 788 { 789 $crlf = "\r\n"; 790 $output = '<?xml version=\'1.0\'?>' . $crlf . 798 791 '<!DOCTYPE email SYSTEM "http://www.phpguru.org/xmail/xmail.dtd">' . $crlf . 799 792 '<email>' . $crlf . 800 793 Mail_mimeDecode::_getXML($input) . 801 794 '</email>'; 802 795 803 return $output; 804 } 805 806 /** 807 * Function that does the actual conversion to xml. Does a single 808 * mimepart at a time. 809 * 810 * @param object Input to convert to xml. This is a mimepart object. 811 * It may or may not contain subparts. 812 * @param integer Number of tabs to indent 813 * @return string XML version of input 814 * @access private 815 */ 816 function _getXML($input, $indent = 1) 817 { 818 $htab = "\t"; 819 $crlf = "\r\n"; 820 $output = ''; 821 $headers = @(array)$input->headers; 822 823 foreach ($headers as $hdr_name => $hdr_value) { 824 825 // Multiple headers with this name 826 if (is_array($headers[$hdr_name])) { 827 for ($i = 0; $i < count($hdr_value); $i++) { 828 $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value[$i], $indent); 829 } 830 831 // Only one header of this sort 832 } else { 833 $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value, $indent); 834 } 835 } 836 837 if (!empty($input->parts)) { 838 for ($i = 0; $i < count($input->parts); $i++) { 839 $output .= $crlf . str_repeat($htab, $indent) . '<mimepart>' . $crlf . 840 Mail_mimeDecode::_getXML($input->parts[$i], $indent+1) . 841 str_repeat($htab, $indent) . '</mimepart>' . $crlf; 842 } 843 } elseif (isset($input->body)) { 844 $output .= $crlf . str_repeat($htab, $indent) . '<body><![CDATA[' . 845 $input->body . ']]></body>' . $crlf; 846 } 847 848 return $output; 849 } 850 851 /** 852 * Helper function to _getXML(). Returns xml of a header. 853 * 854 * @param string Name of header 855 * @param string Value of header 856 * @param integer Number of tabs to indent 857 * @return string XML version of input 858 * @access private 859 */ 860 function _getXML_helper($hdr_name, $hdr_value, $indent) 861 { 862 $htab = "\t"; 863 $crlf = "\r\n"; 864 $return = ''; 865 866 $new_hdr_value = ($hdr_name != 'received') ? Mail_mimeDecode::_parseHeaderValue($hdr_value) : array('value' => $hdr_value); 867 $new_hdr_name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $hdr_name))); 868 869 // Sort out any parameters 870 if (!empty($new_hdr_value['other'])) { 871 foreach ($new_hdr_value['other'] as $paramname => $paramvalue) { 872 $params[] = str_repeat($htab, $indent) . $htab . '<parameter>' . $crlf . 873 str_repeat($htab, $indent) . $htab . $htab . '<paramname>' . htmlspecialchars($paramname) . '</paramname>' . $crlf . 874 str_repeat($htab, $indent) . $htab . $htab . '<paramvalue>' . htmlspecialchars($paramvalue) . '</paramvalue>' . $crlf . 875 str_repeat($htab, $indent) . $htab . '</parameter>' . $crlf; 876 } 877 878 $params = implode('', $params); 879 } else { 880 $params = ''; 881 } 882 883 $return = str_repeat($htab, $indent) . '<header>' . $crlf . 884 str_repeat($htab, $indent) . $htab . '<headername>' . htmlspecialchars($new_hdr_name) . '</headername>' . $crlf . 885 str_repeat($htab, $indent) . $htab . '<headervalue>' . htmlspecialchars($new_hdr_value['value']) . '</headervalue>' . $crlf . 886 $params . 887 str_repeat($htab, $indent) . '</header>' . $crlf; 888 889 return $return; 890 } 891 892 /** 893 * Z-Push helper to decode text 894 * 895 * @param string current charset of input 896 * @param string input 897 * @return string XML version of input 898 * @access private 899 */ 900 function _fromCharset($charset, $input) { 901 if($charset == '' || (strtolower($charset) == $this->_charset)) 902 return $input; 903 904 return @iconv($charset, $this->_charset. "//TRANSLIT", $input); 905 } 906 907 /** 908 * Z-Push helper for error logging 909 * removing PEAR dependency 910 * 911 * @param string debug message 912 * @return boolean always false as there was an error 913 * @access private 914 */ 915 function raiseError($message) { 916 debugLog("mimeDecode error: ". $message); 917 return false; 918 } 796 return $output; 797 } 798 799 /** 800 * Function that does the actual conversion to xml. Does a single 801 * mimepart at a time. 802 * 803 * @param object Input to convert to xml. This is a mimepart object. 804 * It may or may not contain subparts. 805 * @param integer Number of tabs to indent 806 * @return string XML version of input 807 * @access private 808 */ 809 function _getXML($input, $indent = 1) 810 { 811 $htab = "\t"; 812 $crlf = "\r\n"; 813 $output = ''; 814 $headers = @(array)$input->headers; 815 816 foreach ($headers as $hdr_name => $hdr_value) { 817 // Multiple headers with this name 818 if (is_array($headers[$hdr_name])) { 819 for ($i = 0; $i < count($hdr_value); $i++) { 820 $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value[$i], $indent); 821 } 822 823 // Only one header of this sort 824 } else { 825 $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value, $indent); 826 } 827 } 828 829 if (!empty($input->parts)) { 830 for ($i = 0; $i < count($input->parts); $i++) { 831 $output .= $crlf . str_repeat($htab, $indent) . '<mimepart>' . $crlf . 832 Mail_mimeDecode::_getXML($input->parts[$i], $indent+1) . 833 str_repeat($htab, $indent) . '</mimepart>' . $crlf; 834 } 835 } elseif (isset($input->body)) { 836 $output .= $crlf . str_repeat($htab, $indent) . '<body><![CDATA[' . 837 $input->body . ']]></body>' . $crlf; 838 } 839 840 return $output; 841 } 842 843 /** 844 * Helper function to _getXML(). Returns xml of a header. 845 * 846 * @param string Name of header 847 * @param string Value of header 848 * @param integer Number of tabs to indent 849 * @return string XML version of input 850 * @access private 851 */ 852 function _getXML_helper($hdr_name, $hdr_value, $indent) 853 { 854 $htab = "\t"; 855 $crlf = "\r\n"; 856 $return = ''; 857 858 $new_hdr_value = ($hdr_name != 'received') ? Mail_mimeDecode::_parseHeaderValue($hdr_value) : array('value' => $hdr_value); 859 $new_hdr_name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $hdr_name))); 860 861 // Sort out any parameters 862 if (!empty($new_hdr_value['other'])) { 863 foreach ($new_hdr_value['other'] as $paramname => $paramvalue) { 864 $params[] = str_repeat($htab, $indent) . $htab . '<parameter>' . $crlf . 865 str_repeat($htab, $indent) . $htab . $htab . '<paramname>' . htmlspecialchars($paramname) . '</paramname>' . $crlf . 866 str_repeat($htab, $indent) . $htab . $htab . '<paramvalue>' . htmlspecialchars($paramvalue) . '</paramvalue>' . $crlf . 867 str_repeat($htab, $indent) . $htab . '</parameter>' . $crlf; 868 } 869 870 $params = implode('', $params); 871 } else { 872 $params = ''; 873 } 874 875 $return = str_repeat($htab, $indent) . '<header>' . $crlf . 876 str_repeat($htab, $indent) . $htab . '<headername>' . htmlspecialchars($new_hdr_name) . '</headername>' . $crlf . 877 str_repeat($htab, $indent) . $htab . '<headervalue>' . htmlspecialchars($new_hdr_value['value']) . '</headervalue>' . $crlf . 878 $params . 879 str_repeat($htab, $indent) . '</header>' . $crlf; 880 881 return $return; 882 } 883 884 /** 885 * Z-Push helper to decode text 886 * 887 * @param string current charset of input 888 * @param string input 889 * @return string XML version of input 890 * @access private 891 */ 892 function _fromCharset($charset, $input) { 893 if($charset == '' || (strtolower($charset) == $this->_charset)) 894 return $input; 895 896 return @iconv($charset, $this->_charset. "//TRANSLIT", $input); 897 } 898 899 /** 900 * Z-Push helper for error logging 901 * removing PEAR dependency 902 * 903 * @param string debug message 904 * @return boolean always false as there was an error 905 * @access private 906 */ 907 function raiseError($message) { 908 debugLog("mimeDecode error: ". $message); 909 return false; 910 } 919 911 } // End of class
Note: See TracChangeset
for help on using the changeset viewer.