1# -- 2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/ 3# -- 4# This software comes with ABSOLUTELY NO WARRANTY. For details, see 5# the enclosed file COPYING for license information (GPL). If you 6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. 7# -- 8 9package Kernel::System::FetchMail; 10 11use strict; 12use warnings; 13 14use IPC::Open3; 15use Symbol; 16 17our @ObjectDependencies = ( 18 'Kernel::System::Log', 19 'Kernel::Config', 20); 21 22=head1 NAME 23 24Kernel::System::FetchMail - FetchMail wrapper functions 25 26=head1 DESCRIPTION 27 28Functions for email fetch. 29 30 31=head2 new() 32 33create a FetchMail object. Do not use it directly, instead use: 34 35 my $FetchMailObject = $Kernel::OM->Get('Kernel::System::FetchMail'); 36 37=cut 38 39sub new { 40 my ( $Type, %Param ) = @_; 41 42 # allocate new hash for object 43 my $Self = {}; 44 bless( $Self, $Type ); 45 46 return $Self; 47} 48 49=head2 Fetch() 50 51Retrieves messages from an email server using fetchmail backend. 52 53 my $Success = $FetchMailObject->Fetch( 54 55 # General Options: 56 Check => 1, # Optional, check for messages without fetching 57 Silent => 1, # Optional, work silently 58 Verbose => 1, # Optional, work noisily (diagnostic output) 59 NoSoftBounce => 1, # Optional, fetchmail deletes permanently undeliverable messages. 60 SoftBounce => 1, # Optional, keep permanently undeliverable messages on server (default). 61 62 # Disposal Options: 63 Keep => 1, # Optional, save new messages after retrieval 64 NoKeep => 1, # Optional, delete new messages after retrieval 65 Flush => 1, # Optional, delete old messages from server 66 LimitFlush => 1, # Optional, delete oversized messages 67 68 # Protocol and Query Options: 69 Protocol => 'imap', # Optional, (auto || pop2 || pop3 || apop || rpop || kpop || sdps 70 # || imap || etrn || odmr) specify retrieval protocol 71 UIDL => 1, # Optional, force the use of UIDLs (pop3 only) 72 Service => 123, # Optional, TCP service to connect to (can be numeric TCP port) 73 Principal => 'SomePrincipal', # Optional, mail service principal 74 Timeout => 123, # Optional, server nonresponse timeout 75 Plugin => 'SomeCommand', # Optional, specify external command to open connection 76 Plugout => 'SomeCommand', # Optional, specify external command to open smtp connection 77 Folder => 'SomeForlder', # Optional, specify remote folder name 78 TracePolls => 1, # Optional, add poll-tracing information to Received header 79 SSL => 1, # Optional, enable ssl encrypted session 80 SSLCert => 'SomeCertName', # Optional, ssl client certificate 81 SSLKey => 'SomeKeyName', # Optional, ssl private key file 82 SSLProto => 'SSL2', # Optional, (SSL2 || SSL3 || TLS1) force ssl protocol 83 SSLCertCheck => 1, # Optional, do strict server certificate check (recommended) 84 SSLCertFile => 'SomeCerName', # Optional, path to trusted-CA ssl certificate file 85 SSLCertPath => 'SomeCertPath', # Optional, path to trusted-CA ssl certificate directory 86 SSLFingerprint => 'SomeFingerprint', # Optional, fingerprint that must match that of the server's cert. 87 88 # Delivery Control Options: 89 SMTPHost => 'SomeHosts', # Optional, set SMTP forwarding host 90 FetchDomains => 'SomeDomains', # Optional, fetch mail for specified domains 91 SMTPAddress => 'SomeAddress', # Optional, set SMTP delivery domain to use 92 SMTPName => 'some@example.com', # Optional, set SMTP full name username@domain 93 AntiSpam => '123,456', # Optional, set antispam response values 94 MDA => 'SomeCommand', # Optional, set MDA to use for forwarding 95 LMTP => 1, # Optional, use LMTP (RFC2033) for delivery 96 BSMTP => 'SomeFile', # Optional, set output BSMTP file 97 BadHeader => 'reject', # Optional, (reject || accept), specify policy for handling messages with bad headers 98 99 # Resource Limit Control Options 100 Limit => 123, # Optional, don't fetch messages over given size 101 Warnings => 123, # Optional, interval between warning mail notification 102 BatchLimit => 123, # Optional, set batch limit for SMTP connections 103 FetchLimit => 123, # Optional, set fetch limit for server connections 104 FetchSizeLimit => 123, # Optional, set fetch message size limit 105 FastUIDL => 123, # Optional, do a binary search for UIDLs 106 Expunge => 123, # Optional, set max deletions between expunges 107 108 # Authentication Options: 109 Username => 'SomeUserName', # Optional, specify users's login on server 110 Auth => 'ssh', # Optional, (password || kerberos || ssh || otp) authentication type 111 112 # Miscellaneous Options: 113 FetchMailrc => 'SomeFile', # Optional, specify alternate run control file 114 IDFile => 'SomeFile', # Optional, specify alternate UIDs file 115 NoRewrite => 1, # Optional, don't rewrite header addresses 116 Envelope => 'SomeXHeader', # Optional, envelope address header 117 QVirtual => 'SomePrefix', # Optional, prefix to remove from local user id 118 119 # Administrative Options: 120 Postmaster => 'SomeName', # Optional, specify recipient of last resort 121 NoBouce => 1, # Optional, redirect bounces from user to postmaster. 122 ); 123 124Returns: 125 $Success = 1, # or false in case of an error 126 127Note: 128To get more information about the parameters please check fetchmail man pages for the corresponding option 129 130=cut 131 132sub Fetch { 133 my ( $Self, %Param ) = @_; 134 135 # set possible locations for fetchmail bin 136 my @PossibleLocations = ( 137 '/usr/bin/fetchmail', 138 '/usr/sbin/fetchmail', 139 '/usr/local/bin/fetchmail', 140 '/opt/local/bin/fetchmail', 141 ); 142 143 # get SysConfig setting as a fall-back 144 my $ConfigLocation = $Kernel::OM->Get('Kernel::Config')->Get('Fetchmail::Bin') || ''; 145 146 # check if setting is defined and valid 147 if ( $ConfigLocation && $ConfigLocation =~ m{[/|\w]+ fetchmail\z}msx ) { 148 push @PossibleLocations, $ConfigLocation; 149 } 150 151 my $FetchMailBin; 152 153 # set FetMail bin 154 LOCATION: 155 for my $Location (@PossibleLocations) { 156 if ( -e $Location ) { 157 $FetchMailBin = $Location; 158 last LOCATION; 159 } 160 } 161 162 if ( !$FetchMailBin ) { 163 $Kernel::OM->Get('Kernel::System::Log')->Log( 164 Priority => 'error', 165 Message => "FetchMail bin was not found", 166 ); 167 return; 168 } 169 170 my %ParamLookup = ( 171 172 # General Options: 173 Check => '--check', 174 Silent => '--silent', 175 Verbose => '--verbose', 176 NoSoftBounce => '--nosoftbounce', 177 SoftBounce => '--softbounce', 178 179 # Disposal Options: 180 Keep => '--keep', 181 NoKeep => '--nokeep', 182 Flush => '--flush', 183 LimitFlush => '--limitflush', 184 185 # Protocol and Query Options: 186 UIDL => '--uidl', 187 TracePolls => '--tracepolls', 188 SSL => '--ssl', 189 SSLCertCeck => '--sslcertck', 190 191 # Delivery Control Options: 192 LMTP => '--lmtp', 193 194 # Miscellaneous Options: 195 NoRewrite => '--norewrite', 196 197 # Administrative Options: 198 NoBouce => '--nobounce', 199 ); 200 201 my %HasValueParamLookup = ( 202 203 # Protocol and Query Options: 204 Protocol => '--protocol', 205 Service => '--service', 206 Principal => '--principal', 207 Timeout => '--timeout', 208 Plugin => '--plugin', 209 Plugout => '--plugout', 210 Folder => '--folder', 211 SSLCert => '--sslcert', 212 SSLKey => '--sslkey', 213 SSLProto => '--sslproto', 214 SSLCertFile => '--sslcertfile', 215 SSLCertPath => '--sslcertpath', 216 SSLFingerprint => '--sslfingerprint', 217 218 # Delivery Control Options: 219 SMTPHost => '--smtphost', 220 FetchDomains => '--fetchdomains', 221 SMTPAddress => '--smtpaddress', 222 SMTPName => '--smtpname', 223 AntiSpam => '--antispam', 224 MDA => '--mda', 225 BSMTP => '--bsmtp', 226 BadHeader => '--bad-header', 227 228 # Resource Limit Control Options 229 Limit => '--limit', 230 Warnings => '--warnings', 231 BatchLimit => '--batchlimit', 232 FetchLimit => '--fetchlimit', 233 FetchSizeLimit => '--fetchsizelimit', 234 FastUIDL => '--fastuidl', 235 Expunge => '--expunge', 236 237 # Authentication Options: 238 Username => '--username', 239 Auth => '--auth', 240 241 # Miscellaneous Options: 242 FetchMailrc => '--fetchmailrc', 243 IDFile => '--idfile', 244 Envelope => '--envelope', 245 QVirtual => '--qvirtual', 246 247 # Administrative Options: 248 Postmaster => '--postmaster', 249 ); 250 251 # define base command 252 my $Command = "$FetchMailBin -a"; 253 254 OPTION: 255 for my $Option ( sort keys %Param ) { 256 257 next OPTION if !$Param{$Option}; 258 259 # check params without value 260 if ( $ParamLookup{$Option} ) { 261 $Command .= " $ParamLookup{$Option}"; 262 } 263 264 # check params with values 265 elsif ( $HasValueParamLookup{$Option} ) { 266 $Command .= " $HasValueParamLookup{$Option} $Param{$Option}"; 267 } 268 } 269 270 # to capture standard in, out and error 271 my ( $INFH, $OUTFH, $ERRFH ); 272 273 # create a symbol for the error file handle 274 $ERRFH = gensym(); 275 276 # call the command, capturing output and error 277 my $ProcessID; 278 eval { 279 $ProcessID = open3( $INFH, $OUTFH, $ERRFH, $Command ); 280 }; 281 282 my $ErrorMessage; 283 my $ExitCode; 284 285 if ($ProcessID) { 286 287 while (<$ERRFH>) { 288 $ErrorMessage .= $_; 289 } 290 waitpid( $ProcessID, 0 ); 291 $ExitCode = $? >> 8; 292 } 293 else { 294 $ErrorMessage = $@; 295 } 296 297 my $Success = 1; 298 299 # fetchmail ExitCode 1 means no mails to retrieve (this is OK) 300 if ( $ExitCode == 1 ) { 301 $ExitCode = 0; 302 } 303 304 # fetchmail ExitCode 13 means early termination due to limit (this is OK) 305 elsif ( $ExitCode == 13 ) { 306 $Kernel::OM->Get('Kernel::System::Log')->Log( 307 Priority => 'notice', 308 Message => "fetchmail: Poll terminated by a fetch limit", 309 ); 310 $ExitCode = 0; 311 } 312 313 # check if there are errors 314 if ( $ErrorMessage || $ExitCode ) { 315 316 $ErrorMessage //= ''; 317 318 my %ErrorMessageLookup = ( 319 2 => 'Error opening a socket to retrieve mail.', 320 3 => 'User authentication step failed.', 321 4 => 'Fatal protocol error.', 322 5 => 'There was a syntax error in the arguments to fetchmail', 323 6 => 'The run control file had bad permissions.', 324 7 => 'There was an error condition reported by the server.', 325 8 => 'Fetchmail is already running', 326 9 => 'User authentication step failed because the server responded "lock busy", try again later.', 327 10 => 'Fetchmail run failed while trying to do an SMTP port open or transaction.', 328 11 => 329 'Fatal DNS error. Fetchmail encountered an error while performing a DNS lookup at startup and could not proceed.', 330 12 => 'BSMTP batch file could not be opened.', 331 14 => 'Server busy indication.', 332 23 => 'Internal error.', 333 ); 334 335 if ( $ExitCode && !$ErrorMessage ) { 336 $ErrorMessage = $ErrorMessageLookup{$ExitCode} || 'Unknown'; 337 } 338 339 $Kernel::OM->Get('Kernel::System::Log')->Log( 340 Priority => 'error', 341 Message => "There was an error executing $Command: $ErrorMessage", 342 ); 343 344 $Success = 0; 345 } 346 347 return $Success; 348 349} 350 3511; 352 353=head1 TERMS AND CONDITIONS 354 355This software is part of the OTRS project (L<https://otrs.org/>). 356 357This software comes with ABSOLUTELY NO WARRANTY. For details, see 358the enclosed file COPYING for license information (GPL). If you 359did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>. 360 361=cut 362