#!/usr/bin/perl # warranty # perl script for checking Apple warranty/applecare status # # Copyright � 2008,2011 Thomas A. Fine # # Version 1.1 # # Redistribution is permitted, in whole or in part, for commercial and # non-commercial purposes, provided only that this copyright notice # remains. # $plist="/Library/Preferences/com.apple.RemoteDesktop"; $|=1; while (substr($ARGV[0],0,1) eq "-") { $opt=shift(@ARGV); if ($opt eq "-v") { $verbose=1; } elsif ($opt eq "-d") { $debug=1; $verbose=1; } elsif ($opt eq "-p") { $plist=shift(@ARGV); if ($plist =~ /\.plist$/) { $plist =~ s/.plist$//; } } elsif ($opt eq "-f") { if ($#ARGV == -1) { &usage; exit(1); } $field=shift(@ARGV); if ($n>=1) { &usage; exit(1); } } else { &usage; exit(1); } } if ($#ARGV > 0) { &usage; exit(0); } if ($#ARGV > -1) { $serial=shift(@ARGV); } else { $top = &load_sysprof_xml("SPHardwareDataType"); $tmp=${$top}[0]; # Reformulate the mess we get back from this into a cleaner structure foreach $datatype (@{$top}) { $dtname = ${$datatype}{'_dataType'}; #We want the items array, stuff it into a variable with datatype for name @{$dtname}=@{${$datatype}{'_items'}}; } $serial=${$SPHardwareDataType[0]}{'serial_number'}; # This old non-xml way was simpler, but kept breaking with new OSX releases # because things would pop up that would match the pattern. #open(SP,"system_profiler SPHardwareDataType|"); #while(<SP>) { # if (/Serial Number/) { # chop; # s/^.*Serial Number.*:\s*//; # $serial=$_; # } #} #close(SP); } if ($debug) { print "Looking up serial number: >>$serial<<\n"; } #getServiceOptions calls #/ServiceOption.do&serialNo= &SOcountry= #getComponents calls #/Warranty.do&serialNumber= &country= &fullCountryName= #This one worked for a long time #$host='selfsolve.apple.com'; #$port=443; #$path='/Warranty.do'; #$path='/Warranty.do?serialNumber=' . $serial . '&country=USA&fullCountryName=United%20States'; $host='selfsolve.apple.com'; $port=443; $path='/warrantyChecker.do'; $path='/warrantyChecker.do?sn=' . $serial; open(CURL,"curl -s -k 'https://$host:$port$path'|"); while(<CURL>) { $page .= $_; } if ($debug) { print $page, "\n"; } $tmp=$page; $tmp =~ s/^[^{]*{//; $tmp =~ s/}[^}]*$//; $tmp =~ s/\\"/%22/g; #simplify parsing by quoting quoted quotes while (length($tmp)) { $tmp =~ s/^"([^"]*)":"([^"]*)",*//; $a=$1; $b=$2; $b =~ s/%22/"/g; #put back the quoted quotes $data{$a}=$b; if ($debug) { print "$a: $b\n"; } } if ($verbose) { if (length($data{PURCHASE_DATE})) { $start=$data{PURCHASE_DATE}; } elsif (length($data{ESTIMATED_START_DT})) { $start=$data{ESTIMATED_START_DT} . " (estimated)"; } if (length($data{COV_END_DATE})) { $end=$data{COV_END_DATE}; } elsif (length($data{ESTIMATED_END_DT})) { $end=$data{ESTIMATED_END_DT} . " (estimated)"; } print "Serial Number: ", $data{'SERIAL_ID'}, "\n"; print "Product Type : ", $data{'PROD_DESCR'}, "\n"; print "Purchase Date: ", $start, "\n"; print "Covered Thru : ", $end, "\n"; print "Coverage Type: ", $data{'HW_COVERAGE_DESC'}, "\n"; print "Can buy APP? : ", $data{'IS_APP_ELIGIBLE'}, "\n"; #print "Description : ", $data{'HARDWAREMESSAGES'}, "\n"; print "Description : ", $data{'wc.desktopcomputers.hardware.pp.long'}, $data{'wc.portablecomputers.hardware.pp.long'}, "\n"; } else { if (length($data{'COV_END_DATE'})) { print $data{'COV_END_DATE'}, "\n"; } else { print "Passed\n"; } } if (length($field)) { if (length($data{'COVERAGE_DATE'})) { system("defaults write '$plist' $field $data{'COVERAGE_DATE'}"); } else { system("defaults write '$plist' $field 'Passed'"); } print STDERR "Note: changes may not show up in Remote Desktop until ARD agent is restarted\n"; } # # END OF MAIN # sub usage { print STDERR <<EEE; usage: $0 [options] [serial_number] if no serial number is provided it uses the number from the current host Options: -v - verbose -d - debug (show web XML data) -f field - put expiration date into Remote Desktop plist field (usually Text1 through Text4) -p plist - used with -f, use a different plist from the default ($plist) must be full path, without the .plist suffix EEE } # # load_sysprof_xml together with # makeobj, dict, and array are designed to recursively build a structure # of references. an array becomes an array of objects, some of which # are literals (like a string) and some of which are references to other # arrays or dicts (hashes). # # The structure of the system_profiler data is basically # An array, containing one dictionary for each data type # Each dictionary contains some standard keys including: # dataType, which is a literaly string, e.g. SPHardwareDataType # _items, which is an array of the related objects # The first item in _items is dict with the stuff we really want # for example, serial_number # # So what we end up with will be # $top is an arrayref # ${$arrayref}[0] is a dictref # ${...parentref...}{_dataType} is a string, e.g. SPHardwareDataType # ${...parentref...}{_items} is an arrayref # ${...parentref...}[0] is the dict of stuff we want # ${...parentref...}{'serial_number'} is a string # # sub load_sysprof_xml { my $SPtype; while ($#_ >= 0) { $SPtype .= shift(@_) . " "; } my $ret; open(SP,"system_profiler $SPtype -xml|"); while(<SP>) { if (/^\s*<\?xml /) { next; } if (/^\s*<!DOCTYPE /) { next; } if (/^\s*<plist /) { next; } if (/^\s*<\/plist>/) { next; } $ret=&makeobj($_); #print "ret=$ret -- $_\n"; } close(SP); return $ret; } sub makeobj { local ($_)=shift(@_); if (/\s*<array>/) { return(&array); } elsif (/\s*<dict>/) { return(&dict); } elsif (/\s*<array\/>/) { my @foo=(); return(\@foo); } elsif (/\s*<true\/>/) { my $foo="1true"; #actual string, not a reference return($foo); } elsif (/\s*<false\/>/) { my $foo="0false"; #actual string, not a reference return($foo); } elsif (/\s*<string>/) { chop; s/^\s*<string>//; s/<\/string>.*$//; my $foo=$_; #actual string, not a reference return($foo); } elsif (/\s*<integer>/) { chop; s/^\s*<integer>//; s/<\/integer>.*$//; my $foo=$_; #actual string, not a reference return($foo); } elsif (/\s*<date>/) { chop; s/^\s*<date>//; s/<\/date>.*$//; my $foo=$_; #actual string, not a reference return($foo); } else { print "Gosh Darnit, what is this? $_\n"; } } sub array { my @ret=(); my $foo; #$arrayref=[]; while($foo=<SP>) { if ($foo =~ /^\s*<\/array>/) { last; } push(@ret,&makeobj($foo)); #push(@{$arrayref},&makeobj($foo)); } return(\@ret); #return($arrayref); } sub dict { my %ret=(); my $foo; my $key; while($foo=<SP>) { if ($foo =~ /^\s*<key>/) { $key=$foo; chop($key); $key=~ s/^\s*<key>//; $key=~ s/<\/key>.*$//; $foo=<SP>; $ret{$key}=&makeobj($foo); } elsif ($foo =~ /^\s*<\/dict>/) { last; } else { print "Gosh darnit! $foo\n"; } } #print " returning ", join(" ",keys(%ret)), "\n"; return(\%ret); }