Subversion Repositories computer_asset_manager_v1

Rev

Rev 6 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 rodolico 1
<?php
2
 
3
/*
4
 * getSysinfoMail.php
5
 * 
6
 * Author: R. W. Rodolico
7
 * Copyright: 20151002, Daily Data, Inc.
8
 * 
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation, either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
21
 * 
22
 * Read messages from mail server. If they are YAML or XML sysinfo reports
23
 * save them to local drive, then remove them from mail server.
24
 * Files will be named with the following values, separated by underscores
25
 * report date (YYYY-MM-DD)
26
 * report time (HH:MM:SS) (CONTAINS COLONS)
27
 * client name (MAY CONTAIN SPACES)
28
 * device name
29
 * serial number (default to 00000 if it is not in the report)
30
 * 
31
 * Requires php5-imap
32
 * apt-get install php5-imap
33
 * 
34
 * Good information taken from
35
 * http://docstore.mik.ua/orelly/webprog/pcook/ch17_04.htm
36
 * 
5 rodolico 37
 * V1.1 20160203 RWR
38
 * Changed to use yaml for the configuration file. Had to take the
39
 * anonymous functions which parsed the different file types and convert
40
 * them to simpl eval() blocks.
41
 * 
3 rodolico 42
 */
43
 
5 rodolico 44
$VERSION = '1.1';
3 rodolico 45
$MAXDOWNLOAD = 5000; // maximum number of e-mails to download at one time
46
$CLI = isset( $_SERVER["TERM"]); // only set if we are not in a cron job
6 rodolico 47
// where to load the configuration file from
48
$confFileName = "sysinfoRead.conf.yaml";
49
$searchPaths = array( '/etc/camp', '/opt/camp', '/opt/camp/sysinfo', $_SERVER['SCRIPT_FILENAME'], getcwd() );
3 rodolico 50
 
5 rodolico 51
/*
6 rodolico 52
 * function loadConfig
53
 * Parameters $confFileName - the name of the configuration file
54
 *            $searchPaths - an array of paths to be searched
55
 * Returns    An array containing the configuration 
56
 * will search for a configuration file in $searchPaths for $confFileName
57
 * in order (so as to give priorities). The configuration file is
58
 * assumed to be a YAML file
5 rodolico 59
 */
3 rodolico 60
 
6 rodolico 61
function loadConfig ( $confFileName, $searchPaths ) {
3 rodolico 62
 
6 rodolico 63
   /*
64
    * we don't know where the configuration file will be, so we have a list
65
    * below (searchPaths) to look for it. It will load the first one it 
66
    * finds, then exit. THUS, you could have multiple configuration files
67
    * but only the first one in the list will be used
68
    */
3 rodolico 69
 
6 rodolico 70
   $configuration = array();
5 rodolico 71
 
72
 
6 rodolico 73
   foreach ( $searchPaths as $path ) {
74
      if ( file_exists( "$path/$confFileName" ) ) {
75
         print "Found $path/$confFileName\n";
76
         $configuration = yaml_parse_file( "$path/$confFileName" );
77
         #require "$path/$confFileName";
78
         break; // exit out of the loop; we don't try to load it more than once
79
      } // if
80
   } // foreach
81
   return $configuration;
82
}
83
 
5 rodolico 84
/* 
85
 * function    OpenMailbox
86
 * Parameters: $username
87
 *             $password
88
 *             $server
89
 *             $ssl=true
90
 *             $port=null
91
 *             $mailbox='INBOX'
92
 * 
93
 * Returns:    The IMAP instance handle
94
 *             The server string (used by some functions)
95
 */
3 rodolico 96
function OpenMailbox ( $username, $password, $server, $ssl = true, $port=null, $mailbox = 'INBOX' ) {
97
   if ( $port == null )
98
      if ( $ssl ) $port = 993;  else $port = 143;
99
   $server = gethostbyname( $server );
100
   $serverString = "$server:$port/imap";
101
   if ( $ssl ) $serverString .= '/ssl';
102
   $serverString .= '/novalidate-cert';
103
   $serverString = '{' . $serverString . '}' . $mailbox;
104
   $server = imap_open( $serverString, $username, $password );
105
 
106
   return array($server, $serverString);
107
}
108
 
5 rodolico 109
/*
110
 * function  getContents
111
 * Paramters $mail - handle to the connection
112
 *           $n    - the # of the message to get
113
 * Returns   The type of report (yaml,xml,ini)
114
 *           The contents of the above
115
 * 
116
 * See getBody() below
117
 * 
118
 * At the very end, calls getBody, which evaluates the type of file
119
 * for a valid yaml/xml/ini file
120
 */
3 rodolico 121
function getContents ($mail, $n ) {
122
   $body = '';
123
   $st = imap_fetchstructure($mail, $n);
124
   if (!empty($st->parts)) {
125
       for ($i = 0, $j = count($st->parts); $i < $j; $i++) {
126
           $part = $st->parts[$i];
127
           if ($part->subtype == 'PLAIN') {
128
                $body = imap_fetchbody($mail, $n, $i+1);
129
           }
130
        }
131
   } else {
132
       $body = imap_body($mail, $n);
133
   }
134
   return getBody( $body );
135
}
136
 
5 rodolico 137
/*
138
 * function  getBody
139
 * Parameter $body
140
 * Returns   type of report (yaml, ini, xml)
141
 *           contents of the report
142
 * Returns (false,'') if nothing found
143
 * 
144
 * Removes all cruft from the message, leaving only a yaml, xml
145
 * or ini. For example, anything before --- in a yaml file is remove
146
 * as is everything after ..., and in this case, the first return
147
 * would be the string 'yaml' and the second the actual yaml document
148
 */
3 rodolico 149
function getBody ( $body ) {
5 rodolico 150
   global $configuration;
151
   foreach ( $configuration['bodyContents'] as $key => $regexes ) {
3 rodolico 152
      $matches;
153
      $pattern = $regexes['startTag'] . '.*' . $regexes['endTag'];
154
      if ( preg_match( "/$pattern/ms", $body, $matches ) ) 
155
         return array( $key, $matches[0] );
156
   }
157
   return array( false, '' );
158
}
159
 
160
 
5 rodolico 161
/* function makeFileName
162
 * Parameter $data
163
 *           $type - the type of the file
164
 * Returns   properly formatted file name for saving
165
 * 
166
 * The file name is created as a combination of the report date
167
 * client name, hostname and serial number, separated by the underscore
168
 * character. The type of the file is appended, and the configuration
169
 * value for outpath is prepended
170
 */
3 rodolico 171
function makeFileName ( $data, $type ) {
5 rodolico 172
   global $configuration;
173
   $outpath = $configuration['outpath'];
3 rodolico 174
   // we will create filename as yyyy-mm-dd_HH:mm:ss_client_hostname_serial
175
   $date =  empty( $data['report']['date'] ) ? '' : strtotime( $data['report']['date'] ); // store in Unix timestamp
176
   $date = strftime( '%F_%T', $date ); // save a copy of the date in SQL format
177
 
178
   // add client name
179
   $client = empty( $data['report']['client'] ) ? '' : $data['report']['client'];
180
 
181
   // add hostname
182
   $hostname = empty ( $data['system']['hostname'] ) ? '' : $data['system']['hostname'];
183
 
184
   // add serial number if it exists, otherwise use '00000' (5 0's)
185
   $serial = empty ( $data['system']['serial'] ) ? '00000' : $data['system']['serial'];
186
   return ( $date && $client && $hostname && $serial ) ? "$outpath/$date" . '_' . $client . '_' . $hostname . '_' . "$serial.$type" : false;
187
 
188
} 
189
 
5 rodolico 190
/*
191
 * function saveFile
192
 * parameter $filename
193
 *           $contents
194
 *           $timestamp
195
 * returns   Number of bytes written
196
 * 
197
 * Saves $contents to file $filename, then sets the timestamp to
198
 * $timestamp. It is assumed $filename was created by makeFileName
199
 * and $contents is the content of a report. $timestamp is the actual
200
 * report timestamp
201
 */
3 rodolico 202
function saveFile( $filename, $contents, $timestamp ) {
203
   $bytesWritten = file_put_contents( $filename, $contents );
204
   if ( $bytesWritten ) {
205
      if ( ! touch( $filename, $timestamp ) ) logError( "could not set timestamp of $filename to $timestamp" );
206
   }
207
   return $bytesWritten;
208
}
209
 
210
function logError ( $message ) {
5 rodolico 211
   global $configuration;
212
   error_log( "$message\n", 3, $configuration['logFile'] );
3 rodolico 213
}
214
 
215
/**************************************************************************************************************
216
 * Begin Main Program
217
 **************************************************************************************************************/
218
 
6 rodolico 219
// get the configuration
220
$configuration = loadConfig( $confFileName, $searchPaths );
3 rodolico 221
 
222
// ensure the path we want to write to exists
5 rodolico 223
if ( ! is_dir( $configuration['outpath'] ) ) {
224
   if ( ! mkdir( $configuration['outpath'], 0777, true ) ) {
225
      die( "Could not create path " . $configuration['outpath'] . "\n" );
3 rodolico 226
   }
227
}
228
 
229
$listMailboxes =  isset( $argv[1] ) ; // anything passed on cli results in a list of mailboxes instead of the job
230
 
5 rodolico 231
foreach ( $configuration['servers'] as $thisServer ) {
3 rodolico 232
   if ($MAXDOWNLOAD <= 0 ) break;
233
   if ( ! $thisServer['enabled'] ) continue; // ignore anything that is not enabled
234
   print "Working on " . $thisServer['servername'] . "\n";
235
   $messagesToDelete = array(); // trap the UID's of messages to delete, more accurate than using message number
236
   print "Opening " . $thisServer['servername'] . "\n";
237
 
238
   // open the mail server connection. NOTE: the $connectString is used in other functions, so we need to preserve it
239
   list( $server, $connectString ) = OpenMailbox(  $thisServer['username'], 
240
                                                   $thisServer['password'], 
241
                                                   $thisServer['servername'] , 
242
                                                   $thisServer['ssl'],
243
                                                   $thisServer['port'], 
244
                                                   $listMailboxes ? '' : $thisServer['mailbox'] 
245
                                                );
246
   print "Success with $connectString\n";
247
   if ( $listMailboxes ) {
248
      $list = imap_list($server, $connectString, "*");
249
      print_r( $list ); print "\n";
13 rodolico 250
      continue;
3 rodolico 251
   }
252
   $count = 0;
253
   if ( $server ) {
254
      $folderCount = imap_num_msg( $server );
255
      for ( $num = 1; ($num <= $folderCount) && $MAXDOWNLOAD; $num++ ) {
256
         list( $type,$body ) = getContents( $server, $num );
257
         if ( ! $type ) {
258
            logError( "Unknown File Type" );
259
            continue;
260
         }
5 rodolico 261
         $data = eval( $configuration['bodyContents'][$type]['eval'] );
262
         if ( ! $data ) {
3 rodolico 263
            logError( "Unable to parse file" );
264
            continue;
265
         }
266
         if ( !(  $filename  = makeFileName( $data, $type ) ) ) {
267
            logError( "unable to create a file name" );
268
            continue;
269
         }
270
         if ( !(  $bytesWritten = saveFile( $filename, $body, strtotime( $data['report']['date'] ) ) ) ) {
271
            logError( "unable to save file $filename" );
272
            continue;
273
         }
274
         $messagesToDelete[] = imap_uid( $server, $num );
275
         $count++;
276
         if ( $CLI ) print '.'; // only do this if interactive session
277
         $MAXDOWNLOAD--;
278
      } // for
279
      if ( $thisServer['deleteProcessed'] ) {
280
         foreach ( $messagesToDelete as $uid ) {
281
            imap_delete( $server, $uid, FT_UID ) or logError( "Can't delete [$uid]: imap_last_error()" );
282
         }
283
         imap_expunge( $server );
284
      }  // if delete
285
      imap_close( $server );
286
   } else {
287
      print "Could not open server " . $thisServer['servername'] . "\n";
288
   } // if..else
289
   print "\nProcessed $count messages\n\n";
290
} // outer for
291
?>