Oracle oui.exe crash
Che c’è di meglio durante un fine settimana che installare Oracle 10g R2 10.2.0.1.0 su una macchina virtuale con Windows XP?
Lancio l’Oracle Universal Installer, si apre la consueta finestrella DOS con alcune righe diagnostiche e dopo qualche secondo il crash.
Primi pensieri: sto installando su un sistema operativo non supportato, per giunta virtuale, non ho abbastanta memoria (2Gb fisica, 1Gb assegnato alla VM), la cache del sistema operativo è troppo piccola, ecc.
Nulla di tutto ciò: la causa del problema è che stavo lanciando il setup.exe dello Universal Installer da un path contenente degli spazi al suo interno (tipo “c:\temp\oracle 10g R2″).
Ho rinominato le cartelle eliminando gli spazi e l’installazione è partita regolarmente.
Grazie all’ignoto benefattore di A Different Projection
Ah, oracle!
Progetto GTalk Bot #3
Nell’ultimo mese il progetto GTalk Bot è proseguito seguendo ramificazioni inattese ma assai feconde.
Quei quattro lettori che mi seguono sapranno senz’altro di che progetto sto parlando. Per gli ospiti di passaggio è disponibile la serie delle due puntate precedenti (parte #1 e parte #2)
Nella versione attuale (ancora piuttosto alfa) il bot ha migliorato il supporto LDAP e ora accetta anche query complesse, permettendo amenità varie come estrarre la lista di tutti i riporti di un determinato manager con un comando del tipo:
d -q "manager=Mario Rossi"
Vi ricordo che la sintassi è totalmente arbitraria (il "dir" del post precedente si è contratto in "d" per comodità di digitazione sui dispositivi mobili)
Visto che un pezzo della Corporation sta su Active Directory ho dovuto estendere il supporto delle query LDAP su un secondo server, cosa che, con l’aiuto di uno dei tanti tool di esplorazione LDAP, è risultata particolarmente semplice in quanto l’unica modifica ha riguardato la modalità di autenticazione e il “base dn”.
Ma la cosa di cui vado particolarmente fiero è l’interfaccia con Outlook 2007 (o meglio Exchange 2007) implementata tramite invocazione dei web services di Exchange su protocollo SOAP, risultato che mi è costato qualche notte insonne e un cambio abbastanza radicale in termini di design.
Python e SOAP
L’idea iniziale di utilizzare una soluzione basata su weboutlook si è rivelata poco praticabile e un po’ troppo rozza (sostanzialmente effettua un parsing della pagina web di Outlook Web Access).
I web services di Exchange di 2007 sono invece splendidamente documentati. Il problema quindi si “riduceva” a implementare in Python (il linguaggio con cui avevo iniziato a sviluppare il bot) le chiamate SOAP ai servizi di Exchange.
Seguendo l’eccellente introduzione di Dive Into Python ho cominciato a sperimentare SOAP su python. Dopo aver appreso le basi, ho tentato di attaccare i web services di Exchange con scarsi e snervanti risultati. Purtroppo il debugging di una applicazione SOAP non è per niente banale. Le librerie SOAP di Python che vanno per la maggiore sono due:
- SOAPpy: abbastanza semplice da usare scarsamente documentata e credo non più sviluppata
- ZSI: ben documentata (ma vi serve qualche base di SOAP) e attivamente sviluppata
Quando dal debugging della mia applicazione sono passato al debugging delle librerie medesime per risalire alla causa di certi errori (anche il passaggio dei tipi di variable complessi via SOAP può diventare un incubo) ho pensato che forse il supporto SOAP di Python non era sufficientemente maturo per i miei scopi.
Php
L’articolo Talking SOAP with Exchange ha attirato la mia attenzione su Php che già conoscevo come linguaggio di scripting per applicazioni web.
Vi si descrive più o meno quello che mi serviva, ossia implementare un client SOAP per servizi Exchange 2007. Il ché mi ha indotto a considerare l’ipotesi di scrivere in Php un front-end semplificato per i servizi di Exchange e fare in modo che il bot Gtalk scritto in Python consumasse questi web services surrogati invece degli originali più complessi.
In realtà Php, dalla versione 4.3.0, può essere utilizzato anche per realizzare script eseguibili dalla linea di comando senza necessariamente utilizzarlo all’interno di un web server, assumendo così dignità di linguaggio di scripting di sistema alla pari di python, perl ecc.
Mi sono pertanto chiesto se per caso qualche anima pia non avesse anche provveduto a sviluppare un supporto Php per XMPP/Jabber, il protocollo di Google Talk.
Si dà il caso che grazie al lavoro Nathan Fritz (per sempre grato,Nat!), Php supporti il protocollo XMPP/Jabber.
A quel punto, l’idea di scrivere il GTalk Bot in Php ha preso forma.
Mi spiaceva un po’ abbandonare l’approccio di python-jabberbot e il suo elegante meccanismo di funzioni callback e quindi, come prima cosa, ho riscritto jabberbot in Php (a breve penso di pubblicarlo su Google Code).
Con il php-jabberbot, creare un bot Google Talk che ritorni lo user Id del proprio interlocutore e dica che ore sono è semplice come scrivere:
<?php
include "jabberbot.php";
class GtalkBot extends JabberBot {
public function bot_hello($msg,$args) {
list($jid,$client)=split("/",$msg['from']);
return "Hello $jid , it is now ".strftime("%H:%M:%S %d/%b/%Y");
}
}
$gtb = new GtalkBot(<username_gtalk>,<password_gtalk>');
$gtb->serve_forever();
?>
Collegandosi a Google Talk con un secondo account e aprendo una chat con l’utente fittizio utilizzato dal bot, digitando il messaggio “hello”, il nostro amico risponderà salutandovi cortesemente e ragguagliandovi circa ora e data in uso sul proprio server.
Se avete urgenza di mettere le mani sul codice di php-jabberbot è sufficiente che lasciate un commento a questo post.
Php e NuSOAP
Torniamo a SOAP ed Exchange. L’articolo Talking SOAP with Exchange sopracitato è un ottima introduzione al tema ma ha il difetto di basarsi sull’estensione SOAP di PHP 5 che non supporta l’autenticazione NTLM richiesta da Exchange (l’articolo fornisce anche la soluzione a questo problema).
In realtà, di librerie SOAP per Php ve ne sono almeno tre:
- la già citata estensione SOAP di PHP 5 (su Windows è la dll php_soap.dll)
- il package PEAR:Soap
- la libreria NuSOAP (la versione che ho scaricato dal repository reca numero 0.7.3)
La terza è quella con cui mi sono trovato meglio: buona documentazione, supporto autenticazione NTLM nonché Basic HTTP e sufficiente diagnostica per il debugging.
Ho quindi iniziato a sperimentare NuSOAP con alcuni web services disponibili in rete (per esempio XMethods.net).
Php, NuSOAP e Exchange 2007
Rinfrancato dai primi successi, sono passato a studiare la documentazione disponibile e a fare qualche esperimento infastidendo il nostro server Exchange 2007.
La faccio breve e vi presento qui sotto un esempio di come sia possibile usare NuSOAP per interrogare Exchange e ottenere informazioni sui messaggi non letti presenti nella vostra casella di posta elettronica.
Personalmente ho trovato l’introduzione a SOAP di Dive Into Python (anche se centrata su Python) più che sufficiente per i miei scopi. Qualunque altra introduzione all’argomento va bene. I concetti che vi servono sono il meccanismo Request/Response di SOAP, il modo in cui i messaggi vengono formattati in XML e i descrittori di webservices WSDL.
Le interrogazioni di questo esempio useranno l’approccio WSDL.
Gli ingredienti:
- un server Exchange 2007 (es. https://exchange.example.com) e relativo account; inoltre dovrete farvi dire quale tipo di autenticazione è configurata sul server (nel mio caso Basic HTTP, altra possibile opzione è NTML)
- PHP 5
- NuSOAP 0.7.x: io sto usando la 0.7.3
- Php_curl: l’unica dipendenza richiesta da NuSOAP
Anche se il bot verrà messo in produzione su Linux, in fase di test opero in ambiente Windows: I love scripting languages!
Cominciate a procurarvi i seguenti file dal vostro server Exchange. Dovrebbero essere reperibili agli indirizzi indicati qui sotto:
- Services.wsdl: https://exchange.esempio.com/EWS/Services.wsdl.
- messages.xsd: https://exchange.esempio.com/EWS/messages.xsd
- types.xsd:https://exchange.esempio.com/EWS/types.xsd
Salvateli in una directory locale nel vostro ambiente di sviluppo. Questi file XML contengono le specifiche dei web services esposti da Exchange. Teoricamente non è necessario utilizzarli localmente, tuttavia, secondoTalking SOAP with Exchange, il wsdl di Exchange 2007 è malformato (!) in quanto mancante di una dichiarazione senza la quale non si ha conformità con le specifiche SOAP. In effetti, se provate a usare il file così com’è, le interrogazioni SOAP falliscono. La soluzione più semplice, una volta salvato il file in locale, è aggiungervi in coda la parte mancante come riportato qui sotto e nell’articolo (sostituite ovviamente il nome del server con quello reale):
<wsdl:service name="ExchangeServices">
<wsdl:port name="ExchangeServicePort" binding="tns:ExchangeServiceBinding">
<soap:address location=
"https://exchange.esempio.com/EWS/Exchange.asmx"/>
</wsdl:port>
</wsdl:service>
<!-- la riga successiva dovrebbe già essere nel vostro file WSDL -->
</wsdl:definitions>
Autenticazione
Nel frammento qui sotto, si spiega come usare NuSOAP per autenticarsi in Basic HTTP sul server Exchange:
require_once('nusoap.php');
//percorso dove avete salvato il file wsdl, i file .xsd verranno cercati nella medesima directory:
$client = new nusoap_client('file://c:/Temp/Services.wsdl',true);
$err = $client->getError();
if ($err) {
print "\nClient error". $err . ".\n";
}
//basic HTTP autentication:
$client->setCredentials ('username','password','basic');
Il client è pronto per inviare interrogazioni al server Exchange.
“Request“
Esaminando la documentazione dei web services di Exchange scopriamo che la operation FindItem, ritorna i messaggi contenuti in un determinato folder Outlook.
La richiesta deve rispettare questa struttura:
<FindItem Traversal="Shallow">
<ItemShape>
<t:BaseShape>Default</t:BaseShape>
</ItemShape>
<!-apre la dichiarazione per una condizione di ricerca -->
<Restriction>
<!-apre una clausola di euguaglianza -->
<t:IsEqualTo>
<FieldURI FieldURI="message:isRead"/>
<!-message:isRead deve essere zero,ovvero messaggio non letto-->
<FieldURIOrConstant><Constant Value="0"/>
</FieldURIOrConstant>
</t:IsEqualTo>
</Restriction>
<ParentFolderIds>
<!-identifica il folder-->
<t:DistinguishedFolderId Id="inbox"/>
</ParentFolderIds>
</FindItem>
Con NuSOAP, la “request” qui sopra si può costruire creando diversi oggetti soapval innestati, partendo da quelli più interni:
$BaseShape = new soapval(
// nome dell'oggetto come da struttura sopra:
'BaseShape',
// nome del tipo: si ricava dalla documentazione Microsoft:
'DefaultShapeNamesType',
// valore: si ricava dalla documentazione Microsoft
'AllProperties',
// namespace del tipo:si ricava dalla documentazione Microsoft // ho riscontrato che l'interrogazione fallisce se non // viene specificato
'http://schemas.microsoft.com/exchange/services/2006/types',
// namespace dell'elemento (opzionale):si ricava dalla // documentazione Microsoft
false,
// eventuali attributi dell'elemento
false);
$ItemShape = new soapval ('ItemShape',
'ItemResponseShapeType',
// ItemShape contiene BaseShape come valore:
$BaseShape,
'http://schemas.microsoft.com/exchange/services/2006/messages',
false,
false);
$FieldURI = new soapval('FieldURI',
'PathToUnindexedFieldType',
// l'elemento FieldURI non ha valore bensì un attributo (vedi sotto)
'',
'http://schemas.microsoft.com/exchange/services/2006/types',
false,
// attributo FieldURI dell'elemento FieldURI // incidentalmente hanno lo stesso nome // per la dichiarazione si usa il formato chiave=>valore:
array('FieldURI'=>'message:IsRead'));
$Constant = new soapval('Constant',
'ConstantValueType',
'',
'http://schemas.microsoft.com/exchange/services/2006/types',
false,
array('Value'=>'0'));
$FieldURIOrConstant = new soapval('FieldURIOrConstant',
'FieldURIOrConstantType',
$Constant,
'http://schemas.microsoft.com/exchange/services/2006/types',
false,
false );
$IsEqualTo = new soapval('IsEqualTo',
'IsEqualToType',
array($FieldURI,$FieldURIOrConstant),
'http://schemas.microsoft.com/exchange/services/2006/types',
false,
false);
$Restriction = new soapval('Restriction',
'RestrictionType',
$IsEqualTo,
'http://schemas.microsoft.com/exchange/services/2006/messages',
false,
false);
$DistinguishedFolderId = new soapval('DistinguishedFolderId',
'DistinguishedFolderIdType',
'',
'http://schemas.microsoft.com/exchange/services/2006/types',
false,
array('Id'=>'inbox'));
$ParentFolderIds = new soapval('ParentFolderIds',
'NonEmptyArrayOfBaseFolderIdsType',
$DistinguishedFolderId,
'http://schemas.microsoft.com/exchange/services/2006/messages',
false,
false);
$FindItem = new soapval('FindItem',
'FindItemType',
// quando l'elemento contiene più sottoelementi, // questi vengono combinati in un array:
array($ItemShape,$Restriction,$ParentFolderIds),
'http://schemas.microsoft.com/exchange/services/2006/messages',
false,
array('Traversal'=>'Shallow'));
A questo punto la variabile $FindItem contiene la nostra richiesta. Rimane solo da inviarla al server. Ecco come fare:
$xmlout = $FindItem->serialize('literal');
$items=$client->call('FindItem',$xmlout);
$err = $client->getError();
if ($err) {
print "\nMethod error". $err . ".\n";
}
// nel caso vogliate esaminare la struttura della risposta del server:
//print_r($items);
“Response“
La documentazione di Microsoft riporta anche le specifiche dettagliate delle risposte del server.
Queste vengono astratte da NuSOAP sotto forma di array innestati. Vi rimando alla documentazione o alle prove sul campo per i dettagli.
Mi limito qui a riportare il codice che potete utilizzare per stampare le informazioni relative ai messaggi non letti presenti nella inbox e ritornati nella variabile $items di cui sopra:
// numero di messaggi trovati
$num_items = $items['ResponseMessages']['FindItemResponseMessage']['RootFolder']['!TotalItemsInView'];
// loop sui messaggi: attenzione, questo loop // funziona solo se $num_items > 1. // occorre gestire il caso 0 o 1 messaggio separatamente
foreach ($items['ResponseMessages']['FindItemResponseMessage']['RootFolder']['Items']['Message'] as $message) {
print "Subject: ". $message['Subject']. "\n" .
"From: ". $message['From']['Mailbox']['Name']. "\n" .
"Size: ". $message['Size']. "\n" .
"Date Sent: ". $message['DateTimeSent']. "\n" .
"Date Created: ". $message['DateTimeCreated']. "\n" .
}
Oltre
Ricapitoliamo.
Con questa soluzione posso accedere via instant messaging di GTalk a una serie di servizi disponibili normalmente solo all’interno della nostra rete aziendale, come info LDAP e posta.
In realtà, la recente migrazione ad Outlook 2007 (un altro pianeta rispetto a Lotus Notes) ha reso questa necessità meno impellente in quanto finalmente, dopo anni, possiamo accedere alla nostra posta via Web fuori dalla VPN grazie a Outlook Web Access su https. Ho già sperimentato l’interfaccia utente su iPod Touch (dal Nokia E65 ho un problema di cookie).
L’interrogazione via instant messaging può però in diversi casi essere più agevole e immediata e consentire anche interessanti estensioni che coinvolgano il servizio Twitter. Il bot potrebbe infatti mettersi in ascolto di un account twitter fittizio al quale inviare messaggi via SMS. Questi messaggi verrebbero in realtà interpretati come comandi da eseguire esattamente come se l’interazione avvenisse via IM. Come gestire l’invio delle risposte in questo caso? Ovviamente sempre via SMS, usando una SIM dedicata collegata al server su cui gira il bot o un interessante side effect di Google Calendar.
Ma questo è materiale per il prossimo articolo.
Progetto GTalk Bot #2
Dopo aver migrato il sistema operativo della linux box adibita a server ftp (che spreco!) da Slackware a Ubuntu 8.1 sono ritornato sul vecchio progetto di realizzare un bot GTalk che mi consenta di accedere da qualunque client google talk a informazioni disponibili sollo dall’interno della nostra rete aziendale (posta, informazioni anagrafiche, numeri di telefono, ecc.).
E così, lo scorso fine settimana ho sviluppato un prima versione del bot che, collegandosi a Google Talk con un account opportunamente creato, aspetta che il suo padrone gli invii i comandi ai quali è stato addestrato a rispondere.
Uno di questi comandi, che ho chiamato dir, fa sì che il bot acceda al server aziendale LDAP e restituisca informazioni pubbliche relative dipendenti. La sintassi è:
dir keyword [attribute]
dove keyword identifica la chiave di ricerca nella directory (per esempio il nome e cognome di un utente aziendale o una sua sottostringa) e [attribute] è l’attributo cercato (manager,mobile, location, title, ecc.)
Per esempio, se voglio conoscere il numero di cellulare del collega Mario Rossi, è sufficiente che chieda al mio fido assistente:
dir "Mario Rossi" mobile
Nel caso voglia reperire tutte le informazioni pubbliche di Mario Rossi, basterà invece digitare:
dir "Mario Rossi"
Ovviamente questa piccola magia funziona su qualunque dispositivo che supporti Jabber (il protocollo di IM su cui Google Talk è basato) e io ho potuto provarlo su un iPod Touch (sul quale GTalk gira in modo nativo) e un Nokia E65 con Fring installato.
Dopo essermi baloccato un paio d’ore con pygtalkrobot che ho avuto qualche problema a usare mi sono imbattuto nel progetto python-jabberbot che fornisce praticamente tutto quello che serve.
Il modulo jabberbot.py fornisce una classe JabberBot di cui ho modificato il costruttore per consentire di passare come parametri il server Jabber e la porta di connessione. Nel caso di Google Talk il server è talk.google.com. Dato che dall’interno della nostra rete la connessione con il server gtalk funziona solo attraverso la porta 443 (e non la 5222) e non essendo riuscito a forzare l’uso di questa porta nelle istanze della classe JabberBot ho tagliato corto e consentito di specificarne il valore come parametro.
La classe JabberBot fornisce le primitive per connettersi al server nonché ricevere e inviare messaggi. Il vostro bot deve essere definito come classe ereditata da JabberBot ed esporre metodi aggiuntivi per il trattamento dei messaggi. Il nome del metodo deve essere denominato come bot_<parola_chiave> (bot_ è il prefisso comune a tutti i metodi).
Quando il bot riceve un messaggio in cui la prima parola è <parola_chiave> invocherà il metodo corrispondente per il trattamento del messaggio. Per esempio, per implementare un comando che restituisca il timestamp del server si può usare qualcosa del tipo:
def bot_time( self, mess, args):
"""Displays current server time"""
return str(datetime.datetime.now())
che verrà invocato digitando “time” nella chat con il vostro bot.
Pygtalkrobot usa un approccio simile ma i comandi sono definiti come espressioni regolari. In linea di principio questo approccio è più potente e flessibile ma per i miei scopi l’ho trovato inutilmente complicato.
Per accedere a LDAP ho usato la relativa libreria python-ldap e qualche esempio di query reperito in rete.
Le due revisioni successive dovranno implementare due importanti aggiunte:
- l’interrogazione del mio file di posta tramite l’interfaccia WebOutlook, gentilmente resa disponibile dopo la migrazione della nostra infrastruttura da Lotus Notes a Outlook. Per questo utilizzerò un altro progetto python: weboutlook che va modificato per supportare la Basic HTTP Authentication usata dall’interfaccia web del nostro nuovo server Exchange
- l’esecuzione del bot come demone. Di nuovo mi appoggio sulle spalle dei giganti e mi servo della Chris’ Python Page
Ad maiora!
iPod Touch: sincronizzazione interminabile
Se anche a voi capita che la sincronizzazione dell’iPod Touch con iTunes duri parecchi minuti,
provate a cancellare il contenuto della directory:
C:\Documents and Settings\<user>\Application Data\Apple Computer\Logs\CrashReporter\MobileDevice\<nome ipod>
nota bene: lasciate la directory, cancellate solo il contenuto
Progetto GTalk Bot
Un Internet robot, o più semplicemente bot, è un programma che esegue attività automatizzate e ripetitive accedendo
a informazioni attraverso, perlappunto, Internet.
Un Gtalk bot è un bot che sfruttando un account Google interagisce attraverso Internet con il mondo esterno utilizzando il protocollo standard di instant messaging adottato da Google Talk, ovvero XMMP (già noto come Jabber). Un esempio è il bot GTalk di Twitter che vi consente di pubblicare i vostri twitties o leggere quelli delle persone di cui siete followers (nota: Twitter sta avendo in questo periodo seri problemi di performance e il bot e altri servizi sono disattivati da un paio di giorni). Oppure la serie di robot traduttori sviluppati da Google come En2It che traduce parole dall’inglese all’italiano.
Ingredienti:
- un account Google, chiamiamolo GBot
- un computer collegato permanentemente a Internet
- un programma in grado di comprendere e processare messaggi basati XMMP
Il programma si collega al server Google Talk con l’account GBot e rimane in ascolto, in attesa di messaggi. In linea di principio, qualunque client connesso con il server GTalk può tentare di interloquire con il mio programma. In realtà sarà bene implementare delle politiche di filtro per evitare abusi e accettare messaggi solo da account Google predefiniti.
Dato che ho intenzione di far girare questo bot nella mia rete aziendale, esso potrà avere accesso a informazioni che potrebbero farmi comodo in situazioni in cui non ho accesso alla VPN e implementare altri utili servizi come:
- visualizzare la lista degli ultimi mail ricevuti sul mio account di posta aziendale
- recuperare il numero di telefono di un collega accedendo alla corporate directory
- spedire via fax documenti allegati a messaggi di posta elettronica (sfruttando la macchina fax che è anche configurata come stampante virtuale, probabilmente dovrò scomodare SAMBA)
- …
Un ottimo punto di partenza è il programma didattico Todotxt (scritto in python) che implementa un GTalk bot in grado di gestire una todolist (se volete fare delle prove da dietro un firewall, potreste dover modificare la porta di connessione al server Google Talk da 5222 a 443).
Note per lo sviluppatore:
- valutare alternative a python (es. la libreria java Smack)
- valutare implicazioni di sicurezza: documentarsi su possibili attacchi a bot jabber
- cifratura del traffico?
- struttura modulare: funzione o gruppo di funzioni = plugin
Emmò butto giù un paio di user requirements.

