Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

« Newer Snippets
Older Snippets »
Showing 1-10 of 60 total  RSS 

Interactive Text-to-Speech (Windows, Perl)

This script calls the Windows OLE for the built in TTS. Type what you want the computer to say at the prompt and hit enter. To quit type ":q" (minus the quotation marks).


use Win32::OLE qw( EVENTS );

get_text();

sub get_text{
	$output_speech = <STDIN>;
	chomp($output_speech);
	if($output_speech ne ":q"){
		say_this();
		get_text();
	}
}

sub say_this{
	my $myTTS = new Win32::OLE( "Sapi.SpVoice" ); 
	$myTTS->Speak( "$output_speech" );
	while( $myTTS->{Speaking} )
	{
		Win32::OLE->SpinMessageLoop();
		Win32::Sleep( 100 );
	}
}

Find & Replace in Word Document with Ruby

I use this to open a "template" (really just a plain Word document with [text to replace] inside), do the substitutions, and save as a new filename.

require 'win32ole'

word = WIN32OLE.new('Word.Application')
#word.Visible = true # uncomment if you want to see it happen
doc = word.Documents.Open('c:\file_to_open.doc')
{
  'name' => 'Tim Morgan',
  'date' => Date.today.strftime('%B %d, %Y'),
  ...
}.each do |key, value|
  word.Selection.HomeKey(unit=6) # start at beginning
  find = word.Selection.Find
  find.Text = "[#{key}]" # text must be in square brackets
  while word.Selection.Find.Execute
    word.Selection.TypeText(text=value)
  end
end
doc.SaveAs('c:\output_file.doc')
doc.Close

Internet Explorer automation using win32::OLE

// Sample code used for one of my client
#!/usr/bin/perl -w

use strict;
use Data::Dumper;
use Win32::OLE qw( EVENTS );

my ($day, $mon, $year, $hour, $min, $sec) = (localtime)[3, 4, 5, 2, 1, 0];
$mon++; # 0-based index
$year = $year + 1900;
my $date = sprintf ("%04i-%02i-%02i %02i\:%02i\:%02i", $year, $mon, $day, $hour, $min, $sec);

my $Disconnect;
my $Menu;
my $TreeView;
my $WatchDog;
my $MenuClicked=0;

my $ScenarioCompleted=0;

my @TreeViewLinks=("Appareillage du B","Branchement Comptage","Branchement individuel");
my $Previouslink=$TreeViewLinks[0];

my $ie = Win32::OLE->new( 'InternetExplorer.Application' ) or die "error starting IE";
$ie->{visible} = 1;

Win32::OLE->Option( Warn => 3 );

$WatchDog=time();
Win32::OLE->WithEvents( $ie, \&Event, 'DWebBrowserEvents2' );
$ie->navigate( 'http://www.xxx.fr' );
Win32::OLE->MessageLoop();
unlink("noemis.err") if -f "noemis.err";
if ( ! $ScenarioCompleted ) {
	open( ERR , ">noemis.err" ); 
	print ERR "Problem executing Noemis scenario, please check www.xxx.fr.\n" ;
	close(ERR);
}
$Disconnect->Click();
Win32::OLE->SpinMessageLoop;

# Maintenance du fichier historique
open ( STATS , "noemis.txt" );
my @lines=<STATS>;
close (STATS);
open( STATS , ">noemis.txt" ); 
for my $line (@lines) {
	my ($datetime) = split ( /;/ , $line );
	my ($h_year,$h_mon) = $datetime =~ /^([0-9]{4})-([0-9]{2})/;
	print STATS $line if ($year*12+$mon) - ($h_year*12+$h_mon) < 2;
}
print STATS join(";",$date,"Noemis Scenario",( time() - $WatchDog ))."\n";
close( STATS );

sleep 2;
Win32::OLE->SpinMessageLoop;
sleep 1;
$ie->Quit();
exit 0;


sub Event {
	my ($Obj,$Event,@Args) = @_;
	my $IEObject = shift @Args;
	print " Event triggered: $Event\n";    

	my ($i,$anchor);
	my $anchors;
    
	# STEP 1 : Find the main menu, login to the web site, find the treeview
	if ($Event eq "DocumentComplete") {    
		print "URL: " . $IEObject->Document->URL . "\n";
		if ( $IEObject->Document->URL eq "http://www.xxx.fr/ident.aspx" ) {
			my $forms = $IEObject->Document->forms;
			my $form = $forms->item(0);
			if ( defined($form->elements("fldNumCli")) ) {
				print "--------------------------------------------\n";
				print "Found the login box, authenticating ...\n";
				print "--------------------------------------------\n";
			    $form->elements("fldNumCli")->{value} = "xxxx";
			    $form->elements("fldUtil")->{value} = "xxx";
			    $form->elements("fldPwd")->{value} = "xxx";
		    	$form->elements("btIdent")->Click();
	    		}
		}
		if ( $IEObject->Document->URL eq "http://www.xxx.fr/menu.aspx" ) {
			print "Found the menu.\n";
			$Menu = $IEObject->Document;
			$anchors = $IEObject->Document->links;
			for (my $i=0; $i < $anchors->length; $i++) {
				$anchor = $anchors->item($i);
				print $anchor->href."\n";
				$Disconnect = $anchor if $anchor->href eq "http://www.xxx.fr/ident.aspx?qs=deconnecter";
			}
	      	}	    
		if ( $IEObject->Document->URL eq "http://www.xxx.fr/client/frameTreeview.aspx" ) {
			print "Found the TreeView.\n";
			$TreeView = $IEObject->Document;
      		}		
	}

	# STEP 2 : Click on the Menu and TreeView links   
	if ($Event eq "DocumentComplete") {    		
	if ( ! $MenuClicked and defined($Menu) ) {
		my $MenuItem = $Menu->getElementById("SM_CLIE_RECH");
		if ( defined($MenuItem) ) { 
			print $MenuItem->ID."\n";
			$MenuItem->Click;
			$MenuClicked = 1;
		}
	}}

	if ( $Event eq "CommandStateChange" or $Event eq "StatusTextChange" ) {
		print Dumper($IEObject);
	}
	if ( @TreeViewLinks != 0 and 
	     defined($TreeView) and 
	     $Event eq "DocumentComplete" 
	) {
		my $link = shift(@TreeViewLinks);
		$anchors = $TreeView->links;
		my $found=0;
		print "Looking for '$link' in the TreeView ... \n";
	        for (my $i=0; $i < $anchors->length; $i++) {
		       	$anchor = $anchors->item($i);
	        	#print $anchor->innerHTML."\n";
		       	if ( $anchor->innerHTML =~ /$link/ ) {
				print "Clicking on '$link' ... \n";
	                	$anchor->Click;
				$found=1;
				$Previouslink=$link;
				last;
			}
	        }
		if ( ! $found ) { 
			# Le TreeView a bugge, on reclique
			sleep 1;
			print "Looking for '$Previouslink' in the TreeView ... \n";
		        for (my $i=0; $i < $anchors->length; $i++) {
			       	$anchor = $anchors->item($i);
	        		#print $anchor->innerHTML."\n";
		       		if ( $anchor->innerHTML =~ /$Previouslink/ ) {
					print "Clicking on '$Previouslink' ... \n";
	              		  	$anchor->Click;
					last;
				}
		        }
			unshift @TreeViewLinks,$link;
		}
	} 
   
	# STEP 3 : Verify the list displayed 
		
	if ($Event eq "DocumentComplete") {    
   		if ( @TreeViewLinks == 0 and $IEObject->Document->URL =~ /listeRefPlof.aspx/ ) {
			print "Scenario completed, exiting ...\n";
			$ScenarioCompleted=1;
	   		Win32::OLE->QuitMessageLoop;
		}
	}
    

	# Exit on errors
	    
	Win32::OLE->QuitMessageLoop() if $Event eq "OnQuit" or time() > $WatchDog + 60;
    
}

ASP Page listing and making changes to AD accounts

// Used for automated AD account migration
<HTML><HEAD><TITLE>Workstation User Account migration</TITLE>
<META http-equiv=Content-Type content="text/html; charset=iso-8859-1"><LINK 
href="files/v2006.css" type=text/css rel=stylesheet>
<BODY leftMargin=0 topMargin=30 marginwidth="0" marginheight="0">
<CENTER>
<%
' ------------------------------------------------------------------------
Const ADS_PROPERTY_CLEAR = 1

Const SOURCE_OU="ou=NT Users,ou=NT,dc=fr,dc=erm,dc=int"
Const TARGET_OU="ou=SUPPORT SERVICES,dc=fr,dc=erm,dc=int"

Const HOMES_PATH="\\frsrvfil0001\USERS\"
Const PROFILES_PATH="\\frsrvfil0001\PROFILES\"

Const ADMIN_HOMES_PATH_SOURCE="\\frsrvfil0001\U$\NT\"
Const ADMIN_PROFILES_PATH_SOURCE="\\frsrvfil0001\P$\NT\"
Const ADMIN_HOMES_PATH_DEST="\\frsrvfil0001\U$\"
Const ADMIN_PROFILES_PATH_DEST="\\frsrvfil0001\P$\"

Const SCRIPT_NAME="ntuser_to_xp.asp"

Dim State
State="Init"
Dim OU, Member
 
If Request.QueryString("login") <> "" Then
		' Affichage formulaire pour modif du compte
		State="Info"
End If
If Request.Form("login") <> "" Then
		' On a cliqué sur OK pour valider le formulaire
		State="Modify"
End If
' ------------------------------------------------------------------------
%>
<TABLE cellSpacing=0 cellPadding=1 width=500 align=center bgColor=#26333e 
border=0>
  <TBODY>
  <TR>
    <TD>
      <TABLE cellSpacing=0 cellPadding=1 width=500 align=center border=0>
        <TBODY>
        <TR bgColor=#f0f3f5>
          <TD width=160 valign="top"><IMG height=116 src="files/man_portable.jpg" 
            width=160> </TD>
          <TD width=302 bgColor=#e5ebef>

<%
	If State="Init" Then
	'-----------------------------------------------------------------------------------
	' Listing of the NT Users
	'-----------------------------------------------------------------------------------
%>          

            <TABLE cellSpacing=4 cellPadding=4 width="100%" align=center 
            border=0>
              <TBODY>
              <TR>
                <TD class=medium colSpan=3 height=22>
                    <%
                    'Response.Write(SOURCE_OU & "<BR>") 
                    %>
					Please select the NT 4.0 Workstation user account to migrate
                </TD></TR>
                
              <TR>
                <TD class=td11 height=22>
                                  <%
                  Set OU = GetObject("LDAP://" & SOURCE_OU)
                  OU.Filter = Array("user")
    	          For Each Member In OU
    	          		' Bug with the SMS Account ??
    	          		If Member.Name <> "CN=SMSService" Then 
    	          		If Member.AccountDisabled = 0 Then
	    	                Response.Write("<A HREF=""" & SCRIPT_NAME & "?login=" & Server.URLEncode(Member.Name) & """>" & Member.FullName & "</A><BR>")
	    	            End If
	    	            End If 
            	  Next      
                  
                  %>

                </TD>
                </TR>
                
                </TBODY></TABLE>

<%
End If
%>                
                
<%
	If State="Info" Then
	'-----------------------------------------------------------------------------------
	' Information page about the NT Users
	'-----------------------------------------------------------------------------------
%>          
			<FORM method=post>

            <TABLE cellSpacing=4 cellPadding=4 width="100%" align=center 
            border=0>
              <TBODY>
              <TR>
                <TD class=medium colSpan=2 height=22>
                 	<%
                 	Response.Write("Windows NT 4.0 User Account Migration")
                    %>
					
                </TD></TR>
               
                  <%
                  Sub TabRow(v1,v2)
                  		Response.Write("<TR class=td11 height=16><TD><B>" & v1 & "</B>")
                  		Response.Write("<TD>" & v2 & "</TD>")
                  		Response.Write("</TD></TR>")
                  End Sub
                  Set Member = GetObject("LDAP://" & Request.QueryString("login") & "," & SOURCE_OU)

                  TabRow "User Name",Member.FullName
                  TabRow "NT Login",Member.sAMAccountName
				  TabRow "Login Script", Member.LoginScript & " (to delete)"
				  TabRow "Profile Path", Member.Profile
				  TabRow "New Path",PROFILES_PATH & Member.sAMAccountName
				  TabRow "Home Folder", Member.HomeDirectory
				  TabRow "New Path",HOMES_PATH & Member.sAMAccountName
				  
				  ' Liste des OU dans SUPPORT SERVICES
 				  Dim OUSuppServices, Entity, BoxList
 				  Set OUSuppServices=GetObject("LDAP://" & TARGET_OU)
				  OUSuppServices.Filter = Array("organizationalUnit")
				  BoxList="<SELECT NAME=""entity"">"
				  For Each Entity in OUSuppServices
				  	BoxList= BoxList & "<OPTION VALUE=""" & Entity.Name & """>" & Mid(Entity.Name,4) & "</OPTION>"
				  Next
				  BoxList=BoxList & "</SELECT>"
				  TabRow "Organizational Unit",BoxList
                                    
                  %>

                
                </TBODY></TABLE>
                <BR>
                <INPUT name=login type=hidden value=<% Response.Write(Member.sAMAccountName) %> >
                <INPUT type=image height=18 alt="GO !" width=15 src="files/submit.gif" value=login border=0 name=ok>
                &nbspCliquer ici pour migrer ce compte.<BR><BR>
                ATTENTION, l'utilisateur ne doit pas être connecté ! 
                <% Response.Write("<BR><BR><A HREF=""" & SCRIPT_NAME & """>" & "Cliquer ICI pour annuler" & "</A><BR>") %>
                </FORM>

<%
End If
%>                

<%

	If State="Modify" Then
	'-----------------------------------------------------------------------------------
	' Migration of the NT Users
	'-----------------------------------------------------------------------------------
Sub dirMoveTree(source, dest)
	Response.Write "Deplacement de <B>" & source & " vers " & dest & "</B><BR>"
	Dim Folder,File,SubFolder
	set Folder=fso.GetFolder(source)
	For Each File In Folder.Files
	      Response.Write File.Name & " File -> " & dest & "<BR>"
	      file.move dest & "\"
	Next
	For Each SubFolder In Folder.SubFolders
	      Response.Write SubFolder.Name & " Folder -> " & dest & "<BR>"
	      SubFolder.move dest & "\"
	Next
End Sub

%>          
<CENTER>
Windows NT 4.0 User Account Migration<BR><BR>
<%

' Modification des proprietes l'utilisateur dans AD
Set Member = GetObject("LDAP://" & Request.QueryString("login") & "," & SOURCE_OU)

' ADS_PROPERTY_CLEAR
Member.PutEx 1, "scriptPath", 0
Member.SetInfo

Member.Put "profilePath", PROFILES_PATH & Member.sAMAccountName
Member.Put "homeDirectory", HOMES_PATH & Member.sAMAccountName
' 
Member.SetInfo
' 
Response.Write("Utilisateur <B>" & Member.sAMAccountName & "</B> Modifié dans AD<BR><BR>")

' Deplacement dans le bon conteneur
Set OU = GetObject("LDAP://" & "OU=Users," & Request.Form("entity") & "," & TARGET_OU)
OU.MoveHere "LDAP://" & Request.QueryString("login") & "," & SOURCE_OU, Request.QueryString("login")
Response.Write("Utilisateur <B>" & "LDAP://" & Request.QueryString("login") & "," & SOURCE_OU & "</B> Deplacé dans " & "LDAP://" & "OU=Users," & Request.Form("entity") & "," & TARGET_OU & "<BR><BR>")

DIM fso, File, Folder, SubFolder
Set fso = CreateObject("Scripting.FileSystemObject")

' Creation des repertoires cible

fso.CreateFolder(ADMIN_HOMES_PATH_DEST & Request.Form("login"))
fso.CreateFolder(ADMIN_PROFILES_PATH_DEST & Request.Form("login"))

' Deplacement des données

dirMoveTree ADMIN_HOMES_PATH_SOURCE & Request.Form("login"),ADMIN_HOMES_PATH_DEST & Request.Form("login")
dirMoveTree ADMIN_PROFILES_PATH_SOURCE & Request.Form("login"),ADMIN_PROFILES_PATH_DEST & Request.Form("login")

' Applications des ACLs, en arriere plan car ca peut etre long !
Response.Write("<BR>Creation du script d'application des ACLs C:\Inetpub\wwwroot\techcity\xcacls_" & Request.Form("login") & ".cmd<BR><BR>")
Set server_shell = Server.CreateObject("wscript.shell")

server_shell.Run "cmd /c echo echo Excecution Cacls >C:\Inetpub\wwwroot\techcity\xcacls_" & Request.Form("login") & ".cmd 2>&1",,1
server_shell.Run "cmd /c echo xcacls.exe """ & ADMIN_HOMES_PATH_DEST & Request.Form("login") & """ /T /C /G SYSTEM:F ADMINISTRATORS:F FR-ERM\" & Request.Form("login") & ":C /Y >>C:\Inetpub\wwwroot\techcity\xcacls_" & Request.Form("login") & ".cmd 2>&1",,1
server_shell.Run "cmd /c echo xcacls.exe """ & ADMIN_PROFILES_PATH_DEST & Request.Form("login") & """ /T /C /G SYSTEM:F ADMINISTRATORS:F FR-ERM\" & Request.Form("login") & ":F /Y >>C:\Inetpub\wwwroot\techcity\xcacls_" & Request.Form("login") & ".cmd 2>&1",,1

' server_shell.Run "C:\Inetpub\wwwroot\techcity\xcacls.cmd >C:\Inetpub\wwwroot\techcity\xcacls.log 2>&1",,1
Response.Write("<BR>Les ACLs seront appliquee dans 5 min (scheduled)...<BR><BR>")
Response.Write("Attendre egalement la fin de replication de AD ...<BR><BR>")

Response.Write("<BR>Terminé !<BR>")

%>
<% Response.Write("<BR><BR><A HREF=""" & SCRIPT_NAME & """>" & "Cliquer ICI pour quitter" & "</A><BR>") %>
</CENTER>
<%
End If
%>                


              </TD></TR>            
                
                </TBODY></TABLE></TD></TR>
                        
                
</TBODY></TABLE></CENTER></BODY></HTML>

Simple ASP page to reset passwords

// This page allows to reset an AD account password.
<HTML><HEAD><TITLE>Reinitialisation de mot de passe</TITLE>
<META http-equiv=Content-Type content="text/html; charset=iso-8859-1"><LINK 
href="files/v2006.css" type=text/css rel=stylesheet>
<BODY leftMargin=0 topMargin=30 marginwidth="0" marginheight="0">
<FORM method=post>
<CENTER>
<TABLE cellSpacing=0 cellPadding=1 width=500 align=center bgColor=#26333e 
border=0>
  <TBODY>
  <TR>
    <TD>
      <TABLE cellSpacing=0 cellPadding=1 width=500 align=center border=0>
        <TBODY>
        <TR bgColor=#f0f3f5>
          <TD width=160><IMG height=116 src="files/man_portable.jpg" 
            width=160> </TD>
          <TD width=302 bgColor=#e5ebef>
            <TABLE cellSpacing=4 cellPadding=4 width="100%" align=center 
            border=0>
              <TBODY>
              <TR>
                <TD class=medium colSpan=3 height=22>
                <%
                If Request.Form("login") = "" Then
                	Response.Write("<B>Saisir le compte à reinitialiser</B>")
                Else
                    Dim Group, Member, Domain, UserFound
                    ' 
                    Domain ="FR-ERM"
                    '
                    UserFound=0
                    
	                Set Group = GetObject("WinNT://" & Domain & "/Domain Users")
    	            For Each Member In Group.Members
    	            	' Response.Write(Member.Name & "<BR>")
        	        	If UCase(Member.Name) = UCase(Request.Form("login")) Then
        	        		UserFound=1
        	        		If Member.AccountDisabled Then 
        	        			Response.Write(" " & Request.Form("login") &" est un compte desactive</B>")
        	        			Exit For
        	        		Else
        	        			' Essai de reinit de mot de passe
        	        			Dim res
        	        			res=Member.SetPassword(Request.Form("pass"))
        	        			'Member.Put "pwdLastSet", CLng(0)
        	        			Member.Put "PasswordExpired", 1
								Member.SetInfo
        	        			Response.Write("<B>L'utilisateur "& Request.Form("login") & " a changé de mot de passe !<BR><BR></B>Il devra changer de mot de passe au prochain login.")
        	        			Exit For
        	        		End If
        	        	End If 
            	    Next      
       	        	If UserFound = 0 Then
       	        		Response.Write(Request.Form("login") &" non trouvé dans le domaine "& Domain)
       	        	End If           	            	
                	
                End If
                %>
              
                </TD></TR>
              <TR>
                <TD class=td11 width="1%" height=22>Identifiant
               
                </TD>
                <TD class=td11 colSpan=2>Nouveau mot de passe</TD></TR>
              <TR>
                <TD width="25%"><INPUT maxLength=20 name=login>
 
                </TD>
                <TD width="20%"><INPUT type=password maxLength=10 size=10 
                  name=pass> </TD>
                <TD><INPUT type=image height=18 alt="Reset !" width=15 
                  src="files/submit.gif" value=login border=0 name=ok> 
                </TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></CENTER></FORM></BODY></HTML>

Automating Outlook with Ruby: Inbox & Messages

From the Ruby on Windows blog.

require 'win32ole'
outlook = WIN32OLE.new('Outlook.Application')
mapi = outlook.GetNameSpace('MAPI')

# Get a reference to the Inbox or other folder:
inbox = mapi.GetDefaultFolder(6)
personal_folders = mapi.Folders.Item('Personal Folders')
baseball_folder = personal_folders.Folders.Item('Baseball')

# Get a count of a folder's unread items:
puts "#{inbox.UnreadItemCount} unread messages"

# Iterate over messages in a folder:
inbox.Items.each do |message|
    # Your code here...
end

# Retrieve a single message:
first_message = inbox.Items(1)

# Delete a message:
message.Delete

# Move a message to another folder:
baseball_folder = personal_folders.Folders.Item('Baseball')
message.Move(baseball_folder)

inbox.Items.Count.downto(1) do |i|
    message = inbox.Items(i)
    if message.Subject =~ /cardinals/i
        message.Move(baseball_folder)
    end
end


Further details and discussion can be found here.

Open/Creates a Base Key in the Registry

// open a Base Key in the registry

       public static RegistryKey GetKey(string baseKey)
        {
            RegistryKey key;
            try
            {
                key = Registry.LocalMachine.OpenSubKey(baseKey, true);

                if (key == null)
                {
                    key = Registry.LocalMachine.CreateSubKey(baseKey);
                }
                else
                {
                    MessageBox.Show("Base key resolved");
                }
            }
            catch (Exception e)
            {
                return null;
            }
            return key;
        }

MSSQL 2005 - Add ID value to ID column when INSERTING

// @TableName is obviously the TABLE name u use
// @ColumnName is obviously the COLUMN name u use

---Get next ID number
	DECLARE 
		@ID int
	
	IF (SELECT count(*) FROM @TableName ) > 0
		BEGIN
			SELECT @ID  = max(ColumnName ) from @TableName
			SET @ID = @ID + 1 
		END
	ELSE
	BEGIN
		SET @ID  = 1
	END

Windows XP System Variables

// Windows XP Default System Variables

%SystemDrive%  		C:

%SystemRoot% 		C:\WINNT, C:\WINDOWS

%SystemDirectory% 	C:\WINNT\System32, C:\WINDOWS\System32

%WinDir% 		C:\WINNT, C:\WINDOWS, C:\WINNT\Program Files

%ComSpec% 		C:\WINNT\system32\cmd.exe

%Temp% 			C:\DOCUME~1\Usr\LOCALS~1\Temp from C:\Documents and Settings\Usr\Local Settings\Temp

%HOMEDRIVE% 		C: The drive letter associated with the user's home directory

%HOMEPATH% 		The path to the user's home directory (excluding drive): \Documents and Settings\Guest

%OS% 			Windows_NT -> The operating system the user is running

%USERDOMAIN% 		The name of the domain that contains the user's account

%USERNAME% 		The user's name

flickr to desktop background

// description of your code here

#!/usr/bin/env ruby

########################################
# config
########################################

groups = ['trees']
flick_api_key = 'cc0880a9d309466758fecb6557d7040b'

# proxy just comment out to disable, types: http, sspi
#http_proxy = {:host=> 'name', :port => 80, :type => :sspi}


# temp files for imagemagick
p1 = 'c:/tmp/img.jpg'
p2 = 'c:\\tmp\\img.bmp'

# Imagemagick path
# http://www.imagemagick.org/script/binary-releases.php#windows
# Recommended package: ImageMagick-6.3.5-6-Q8-windows-static.exe
# convert.exe is needed only, so Imagemagick can be uninstalled.
imagick_path = 'convert.exe'

# images with larger/smaller width will be skipped
skip_small = 1000
skip_big = 2100

########################################
# code
########################################

require 'Win32API'
require 'net/http'
require 'win32/sspi'
require 'json'
require 'yaml'
require "win32/open3"
require "win32/process"

def parse_url(url)
  m = /(?:.*?\/\/)(.*?)(\/.*)/.match(url)
  [ m[1] , m[2] ]
end

class NetWrap
  def initialize(p_type = nil, p_host = nil, p_port = nil)
    if !p_type
      @conn = Net::HTTP
    else
      @conn = Net::HTTP.Proxy(p_host, p_port)
    end
    @p_type = p_type
  end
  
  def download(url)
    site, path = parse_url(url)
    data = ''
    @conn.start(site) do |http|
      if @p_type && @p_type == :sspi
        resp, data = Win32::SSPI::NegotiateAuth.proxy_auth_get(http, path)
      else
        resp, data = http.get(path)
      end
    end
    return data
  end
end

class FlickR
  def initialize(apikey, netw)
    @apikey = apikey
    @netw = netw
  end
  
  def request(api_meth,params = {})
    url = "http://api.flickr.com/services/rest/?method=#{api_meth}&api_key=#{@apikey}&format=json"
    params.each {|key,val| url << "&#{key}=#{val}"}
    res = @netw.download(url)
    JSON.parse(res['jsonFlickrApi('.size..-(');'.size)])
  end
  
  def group_photos(id)
    request('flickr.groups.pools.getPhotos', :group_id => id)['photos']['photo']
  end
  
  def group_lookup(name)
    request('flickr.urls.lookupGroup', :url => "http://flickr.com/groups/#{name}/pool/")['group']['id']
  end

  def photo_urls(id)
    request('flickr.photos.getSizes', :photo_id => id)['sizes']['size']
  end
  
  def photo_best(id, width)
    sizes = photo_urls(id).sort {|a,b| a['width'].to_i <=> b['width'].to_i}
    return sizes.find {|x| x['width'].to_i > width} || sizes.last()
  end
end

class ImgList
  def initialize(cfgname)
    @cfg = cfgname
    @saw = {}
    begin
      if f = open(@cfg,'r')
        @saw = YAML.load(f)
        f.close()
        cnt = 0
        @saw.each {|key,val| cnt += 1 if val[1]}
      end
    rescue
    end
  end
  
  def save()
    if f = open(@cfg,'w+')
      f.write(@saw.to_yaml)
      f.close()
    end
  end
  
  def next()
    img = @saw.detect {|x| !x[1]}
    return img[0] if img
    img
  end
  
  def add(url)
    if !@saw.has_key?(url)
      @saw[url] = false
    end
  end
  
  def mark(url)
    @saw[url] = true
  end
  
  def reset()
    @saw.each {|key,val| @saw[key] = false}
  end
end

if defined?(http_proxy)
  netw = NetWrap.new(http_proxy[:type], http_proxy[:host], http_proxy[:port])
else
  netw = NetWrap.new()
end

scr_w = Win32API.new("user32", "GetSystemMetrics", ['I'] , 'I').call(0)

il = ImgList.new('wpcache.yaml')

photo_url = il.next()

if !photo_url
  fr = FlickR.new(flick_api_key, netw)
  groups.each do |group|
    fr.group_photos(fr.group_lookup(group)).each do |x|
      next if !x['ispublic']
      photo = fr.photo_best(x['id'],scr_w)
      next if skip_small && photo['width'].to_i < skip_small
      next if skip_big && photo['width'].to_i > skip_big
      url = photo['source']
      il.add(url)
    end
  end  
  photo_url = il.next()
end

if !photo_url
  il.reset()
  photo_url = il.next()
end

il.mark(photo_url)
il.save()

open(p1,'wb+') { |f|  f.write(netw.download(photo_url)) }

cmdline = "#{imagick_path} -resize #{scr_w} #{p1} bmp3:#{p2}"
Process::waitpid2(Open4::popen4(cmdline)[3])

Win32API.new("user32", "SystemParametersInfo", ['L','L','P','L'] , 'L').Call(20,0,p2,3)