XMLHttpRequest, document element DOM parsing

XMLHttpRequest use, works only if url is on same site.
checklogin.php give <KO/> if login è fails
<OK>XXX</OK> with XXX id of user when login è is ok

var loginOK = false;

var httpRequest;

function validateLogin()
{
 var login = document.getElementById("NomeForm");
 var logintxt = login.value;
 var password = document.getElementById("PasswdForm");
 var passwordtxt = password.value;
 var url = "/forum/checklogin.php?username="
 + logintxt + "&password=" + passwordtxt;

 if (window.XMLHttpRequest) { // Mozilla, Safari, ...
    httpRequest = new XMLHttpRequest();
    if (httpRequest.overrideMimeType) {
       httpRequest.overrideMimeType('text/xml');
    }
 }
 else if (window.ActiveXObject) { // IE
    try {
       httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch (e) {
       try {
          httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
       }
       catch (e) {}
    }
 }

 if (!httpRequest) {
    alert('Giving up :( Cannot create an XMLHTTP instance');
    return false;
 }
 httpRequest.onreadystatechange = loadLogin;
 httpRequest.open('GET', url, true);
 httpRequest.send(null);
}

function loadLogin()
{
  if (httpRequest.readyState == 4) {
      if (httpRequest.status == 200) {
         response = httpRequest.responseText;
	 if (response == "") {
	   alert ('login/password errate.');
	 } else {
	   var responseXML = httpRequest.responseXML.documentElement;
	   user_id = responseXML.firstChild.nodeValue;
	   LinkSitoForm = document.getElementById('LinkSitoForm');
	   LinkSitoForm.setAttribute('value', 'http://forum.cellularmagazine.it/profile.php?mode=viewprofile&u=' + user_id);
	   NomeForm = document.getElementById('NomeForm');
	   PasswdForm = document.getElementById('PasswdForm');
	   PasswdForm.setAttribute('enabled','no');
	   var whchis = document.getElementById("trcheckpasswd");
	   whchis.innerHTML = "OK"
	 }
      } else {
         alert('There was a problem with the request.');
      }
   }
   else {
   }

}

C Language Exception Handling

Error handling

It is common for a program to manage non standard situation, like things does not work as expected, or time is expired on operation, or everything else.

Typically C (as any old language) do manage such situation with error code returned, possible errno setted and a table of string that explain errno (sys_errlist). Thus a typical error management in C require to test any error on functions that may returns error (almost all standard libc functions) and, if error occur, manage it some way.

Contrarily in C++ (and all new object oriented language) there is the exception idiom. This require runtime support that have a cost, and that make, for example, Symbian OS (aka EPOC32) developer decide to drop this support in the name of performance and memory allocation fault tolerance (see TRAPD/Leave mechanism).

Object oriented idiom is not strictly related to object oriented language, generally it is a way to structure your code using the concepts of object model (encapsulation, inheritance, polymorphism). A good example of object oriented library wroten in plain C language is the GIMP Tool Kit. I tend to consider exception handling a part of object idiom, and this part is what is missing in most object oriented libraries.

setjmp() and longjmp() functions

This article will describe what should/could be done in a exceptional _C_ase.
C language miss exception handling support and runtime, does not exists things like C++’s try .. catch, does not exist exception class definition and hierarchy, but there are nice functions like setjmp() and longjmp() that behave someway as try catch …

#include <setjmp.h>
#include <stdio.h>
int 
foo(int p)
{
  if (p) siglongjmp(env,p); /* return to sigstejmp returning p */
  return 0;
}

static sigjmp_buf env;
int
main() {
  int a,r;
  if (!(r=sigsetjmp(env, 1))) {
    for (a=0; a<10; a++) {
      fprintf(stdout,"%d\n",foo(a));
      fflush(stdout);
    }
  } else {
    fprintf(stdout,"exceptionally returned %d",r);
    fflush(stdout);
  }
}

sigsetjmp and siglongjmp are variant conforming to posix and compatible with bsd standard (see GNU Libc documentation)

… yes, it look like try{..}catch(..) in C++ except for the missing catch argument, and that there is only one level of exception

Another example of longjmp

#include <stdio.h>
#include <setjmp.h>

static sigjmp_buf env;
static sigjmp_buf env1;

int
bar(int a)
{
  fprintf(stdout, "bar a:%d\n", a);
  if (a <10) siglongjmp(env1,a);
}

int
foo(int p)
{
  int r;
  if (! (r=sigsetjmp(env1,1))) {
      fprintf(stdout, "foo = %d\n",bar(p+1));
      fflush(stdout);
  } else {
    fprintf(stdout,"some exception occurred %d\n", r);
    fflush(stdout);
    siglongjmp(env,r); /* try with this or without */
  }
  if (f(p)) {
    fprintf(stdout, "well, done");
    fflush(stdout);
  }
  return p;
}

int
f(int p)
{
  if (p>=8) siglongjmp(env,p);  
  if (!(p%2)) return 1;
  return 0;
}
int
main()
{
  int a;
  int r;
  if (! (r=sigsetjmp(env,1))) {
    for (a=0; a<10; a++) {
      fprintf(stdout, "foo = %d\n",foo(a));
      fflush(stdout);
    }
  } else {
    fprintf(stdout,"some exception occurred %d\n", r);
    fflush(stdout);
  }
}

Here f() “raise an exception” that is managed by main, it does that longjmp’ing directly to main setjmp. This is not part of standard exception idiom and in fact make the code unreadable, and this is because use of setjmp/longjmp is almost absent from good code. But position where f() is called make clean that there is a need of different idiom, just because the compiler do not stop if a throwing function is called out of try{..}catch block and here longjmp’ing is not a by pass of a try{..}catch block, contrarily it is just go to the containing try{..}catch block. In other word this other idioma just take all functions as throwing funcs.

Instead of 2 (or more) variables it is better to use a stack of exception managed by utility functions transparently.

An exception stack implementation

For implementation of the exception idiom are needed: a stack of environment and a exception structure. In order to better figure how the things should works the code is better than any graphics:

#include <setjmp.h>
..
int
test_excp()
{
  jmp_buf *my_env;
  exc_struct *my_excp;
  int r;

  my_excp=new_excp();
  my_env = new_env();
  if (!(r=setjmp(my_env))) { /* try */
    a_throwing_func();
    /* other code here
     * ..
     * if at the end all go right free stack and continue */
    free_env(my_env);
  } else { /* catch */
    switch (r) { /* given that type of exception be passed this way */
    case 1: /* 1 is trapped */
      excp_stru *l_excp;
      /* I want l_excp point to the returned exception
       * and also all allocated jmp_buf cleared until 
       * the current one my_env */
      l_excp = compact_excp(my_env);

      /* some management code */
      manage(l_excp);

      break;
    default: /* throw anything else */
      /* just does longjmp to parent level
       * (the parent level do compact exceptions and env) */
      throw_up(my_env);
    }
  }
  free_env(my_env);
  /* in case of uncatched just throw (with parent env) */
  throw_excp(gen_excp, "error");
}

Well, the code does not look so bad. But there is a consideration to take into account: at any given time there is no need of having more than one exception structure filled. This rule in hold even in C++ and Java and any language which have runtime exception: an exception stack is maintained just for tracking purpose, and only if exceptions occurs. I just ignore exception stack and I use a global variable “exception” initialised at start time.

Given the above code, the needed function are:

  • new_env() return a new *jmp_buf
  • free_env(jmp_buf *env) free env_stack till env (included)
  • compact_excp(jmp_buf *) free env_stack till env (excluded)
  • throw_up(my_env) longjmp to the jmp_buf below my_env in env_stack and update env_stack size
  • throw_excp( void(*excp_fill) (struct excp_struct *, va_list ap), … ) this fill last excp_struct exception using excp_fill function and va_list as parameter, the type of the exception will depends on excp_fill behaviour. exception is throw using the jmp_buf on top of env_stack.

Now what is missing is the data type:

typedef 
struct {
  int errno;
  int excp_type;
  void *excp_data;
} exc_struct;

static jmp_buf *env_stack;
excp_struct * exception
int enstack_sz;
int enstack_maxsz;

[enstack(_sz|_max) and env_stack are unpacked, all could be packed, as the interface aims to be transparent]

Performance problems

It seems there are some performance problem here: free_env(jmp_buf *env), compact_excp(jmp_buf *), throw_up(jmp_buf *) all require to walk on env_stack looking at the right env. But, looking at test_excp() function jmp_buf structure is never used (and should be not used) elsewhere out of these “problematic” function. The natural solution is to use an index: the index of the current environment. The same is for exc_struct * variable: throw_excp( void(*excp_fill) (struct excp_struct *, va_list ap), … ) do not need it, and, manage(l_excp) could be replaced (using a simplified c-object idioma) with excp_fun() that take the only exception naturally. Last thing is new_excp() call that is not needed anymore, and new_env() should return an int and do all tricks.

Thus test_excp() example code become:

#include <setjmp.h>
..
int
test_excp()
{
  env_p env;
  int r;

  env = new_env();
  if (!(r=setjmp(get_env(env)))) { /* try */
    a_throwing_func();
  } else { // catch
    switch (r) { /* give that type of exception be passed this way */
    case 1: /* 1 is trapped */
      compact_excp(env);

      /* some management code */
      fprintf(stdout,"%s",gen_excp_get_msg());
      fflush(stdout);

      break;
    default: /* throw anything else */
      /* just does longjmp to parent level 
       * (the parent level do compact exceptions and env) */
      throw_up(env);
    }
  }
  free_env(env);
  /* in case of uncatched just throw (with parent env) */
  gen_excp("error");
  throw_excp();
}

The utility functions

The changed utility function are:

  • new_env() return env_p (env pointer typedef’ed as int)
  • free_env(env_p env) free env_stack till env (included)
  • compact_excp(env_p env) free env_stack till env (excluded)
  • throw_up(env_p env) longjmp to the jmp_buf below env in env_stack
  • throw_excp() longjmp to the top-stack jmp_buf

Also for any exception type it is needed some utility functions:

  • xxx_excp(exc_struct *excp, …) allocate an exception of type xxx in exception (definition of exc_struct is generic enought)
  • xxx_excp_methodX() various methodXs of the exception (get, put ..)

Here the idea is to store the type of exception in the structure and return it as longjmp parameter.

Now the utility function definition:

typedef env_p int;

env_p
new_env()
{
  /* (re)allocate env_stack if needed */
  enstack_sz ++;
  if (enstack_sz > enstack_maxsz) {
    enstack_maxsz = enstack_sz;
    env_stack = (jmp_buf *) realloc(env_stack, enstack_sz * sizeof(jmp_buf));
  }
  return (enstack_sz - 1);
}

#define free_env(env) enstack_sz=env

#define compact_excp(env) enstack_sz=env+1

#define get_env(env) env_stack[env]

inline void
throw_up(env_p env)
{
  longjmp(enstack[env-1], exception->excp_type);
}

inline void
throw_excp()
{
  longjmp(env_stack[enstack_sz - 1], exception->excp_type);
}

void
gen_excp(const char * str)
{
  exception->excp_type = 1;
  exception->excp_data = str;
}

const char *
gen_excp_get_msg()
{
  return (const char *) exception->excp_data;
}

I used inline keyword of c99 standard because I could not use a macro containing longjmp

Here I followed the lazy man rule: “never do action when it is not really needed”

A complete example

#include <stdio.h>
#include <setjmp.h>

/* data type */
typedef 
struct {
  int errno;
  int excp_type;
  void *excp_data;
} exc_struct;

static jmp_buf *env_stack;
exc_struct * exception;
int enstack_sz;
int enstack_maxsz;
typedef env_p int;

void
init_excp()
{
  exception = (exc_struct*) malloc(sizeof(exc_struct));
  enstack_sz=0;
  enstack_maxsz=0;
  env_stack=NULL;
}

void
clean_excp()
{
  if (exception!=NULL) {
    free(exception);
    exception=NULL;
  }
  if (env_stack!=NULL) {
    free(env_stack);
    enstack_sz=0;
    enstack_maxsz=0;
    env_stack=NULL;
  }
}
/* utility funcs */

env_p
new_env()
{
  // (re)allocate env_stack if needed
  enstack_sz ++;
  if (enstack_sz > enstack_maxsz) {
    enstack_maxsz = enstack_sz;
    env_stack = (jmp_buf *) realloc(env_stack, enstack_sz * sizeof(jmp_buf));
  }
  return (enstack_sz - 1);
}

#define free_env(env) enstack_sz=env

#define compact_excp(env) enstack_sz=env+1

#define get_env(env) env_stack[env]

inline void
throw_up(env_p env)
{
  longjmp(enstack[env-1], exception->excp_type);
}

inline void
throw_excp()
{
  longjmp(env_stack[enstack_sz - 1], exception->excp_type);
}

void
gen_excp(const char * str)
{
  exception->excp_type = 1;
  exception->excp_data = str;
}

void
gen2_excp(const char * str)
{
  // assert(exstack_sz == enstack_sz);
  exception->excp_type = 2;
  exception->excp_data = (void *) str;
}

const char *
gen_excp_get_msg()
{
  return (const char *) exception->excp_data;
}
// the test code

void
better_sith(int a)
{
  /* do something ...
   * ..
   * .. if the case throw (after removing unusefull env) */
  if (a%2) {
    gen_excp("(I am better_sith) it is not odd");
    throw_excp();
  }
  if (a==2) {
    gen2_excp("(I am better_sith) I do not like the number 2");
    throw_excp();
  }
}

int
dosome_sith(int a)
{
  if (a<8) {
    env_p env;
    int r;
    // this function's personal exception catch
    env=new_env();

    if (!(r=setjmp(get_env(env)))) { /* try */
      better_sith(a);
    } else {
      if (r == 1) { /* what to catch: 1 gen_ exception */
	compact_excp(env);
	fprintf(stdout,"dosome_sith::exception message: %s\n",
                       gen_excp_get_msg());
	fflush(stdout);
      } else { /* throw everything else */
	throw_up(env);
      }
    }
    free_env(env);
    /* gen_excp("I'm bored, I want return");
       throw_excp();
    */ /* this works too */
  } else {
    gen_excp(
     "(I am dosome_sith) all wrong guy, you should not give me such values");
    throw_excp();
  }
}

int
main()
{
  int a;
  int r;
  env_p env;

  init_excp();

  fprintf(stdout,"INIT PHASE\n");
  fflush(stdout);

  env = new_env();

  if (!setjmp(get_env(env))) {
    for (a=0;a<=10; a++) {
      fprintf(stdout,"main:: I try with %d\n",a);
      fflush(stdout);
      dosome_sith(a);
    }
  } else {
    compact_excp(env);
    fprintf(stdout,"main:: catched exception message: %s\n",
                   gen_excp_get_msg());
    fflush(stdout);
  }
  free_env(env);

  clean_excp();
}

If I exclude the utility, startup and shutdown function, there are no need to use pointer and all is done with less than one hundred line of C code!

Having a better look, there is something that could be tweaked. The first one is: what happen if throw_excp()’ing when no exception is in the stack? This scenario in C++ will make the program to stop, in Java compiler refuse the code, here it could be added an assert() clause before longjmp is called on exception stack. The behaviour is different from C++ because error message on abort is more informative than “this function was called outside of a setjmp block”.

The second question is: why do we have to jump in a setjmp block that do not manage this type of exception? This could be solved using a bitmap of exception but the code will become more expensive than in would be (if compiler implement inline properly) two or three longjmps. (I guess it could not used C preprocessor to make the trick because of definition of setjmp/longjmp, and because of documentation warnings on the use of these “functions”).

Some conclusions

Recalling the begin of this article, from the point of view of a object oriented library wrote in C there is no performance lost on using longjmp instead of just returning an error code, also with a number of exception type working with such library could become very comfortable, as saw there are no need to use pointer out of exception definition and after coding the missing parts (i.e. setting errno when relevant) you can still manage error just asking errno to a generic exception method (i.e. excp_get_errno()). Replacing assert with a test and abort call, when the exception is not managed it cause program to abort, but definitively this is not odd.

Symbian OS C++ framework do not support exception because of efficiency, and, mostly, because of memory cleanup problems, but using the outlined way for exception management and adding a cleanup stack (similar to the symbian os one), using ibstack where necessary, and every trick that came to be useful, this idiom result to be more versatile and as robust as symbian’s one.

The story does not end here. Actually there are some problem that arise when using setjmp/longjmp, i.e. how does interact with posix thread idiom (i.e. at least one exception for thread are needed). To integrate such thing in a complete (and complex enough) library could be not so easy as it could appear.

References

setjmp() and longjmp() functions are defined in POSIX and single unix standard, documentation is in its own man page and info format GNU Libc documentation in GNU systems
Symbian OS is documented in its own site, documentation is distributed as zip package and available on line, also distribuited by symbian vendors (Nokia, Siemens, Sony Ericsson, Motorola, etc.)

Parsing XML: Sax or DOM

I tried both SAX and DOM, for parsing an XML file, difference in time performance is huge, from 4 hours (DOM) to 9 seconds (SAX).

Different APIs

Different interface bring to different complexity of code, but all depends from the point of view

DOM

You do not know what is Document Object Model if you do not know what is an XPath: XPath is a path that match one or more XML element in a XML document.

Example: //product[@title="casa"]

Does match all element with attribute titel=”casa”

Every programming language, and every library give different way to use xpath, however
it consist on make a request for a list of nodes that match a given XPath.
Typically this list of node are used for querying other specific information for every node contained.

For example, if <product> contains child elements or other attributes, one could request a specific
child, maybe throw another XPath.

SAX

(Simple API for XML). The Library has a parser top-down recursive, parser accent as parameter the document and 3 or more callback functions, which parser call when it happen some event with parameter given by the context and event type itself.

The 3 base callback functions are called for events: element start, element end, character data.

(there will be callback for CDATA start, CDATA end, and anything else if library is complete)

The element start callback is called wiht element name the list of attribute.
The element end callback is called with element name. The character callback is called with character list.
(it is needed to refer to the specific documentation)

Differents prospectives

From programming point of view there are 2 differents prospectives. With DOM the document is an object and request are done by methods, such as XPath. With SAX the document is read and parsed for record or use info contained.

Simply, if what is central are data contained in document (all), then I tend to use SAX, else if what is central is to extract some data from a document I tend to use DOM.

DOM Tricks

If I am using DOM, it is better to load document in ram (if not already there). This because reading from file is surely slower.

Other thing, but simple, do not call methods when not needed, reduce number of request to minimum.

Performance

Even loading document on ram performance could be very bad, let consider 2 MBytes XML document. With 200 XPath request for the root, parser have to parse (read and process) 400 MBytes of character, which is a great amount of operations

With SAX document is read once, it does not care to load it in ram before (given the fact parser is descending recursive). All info have to be recorded in some data structure locale to the code. Once parsing is ended, those data will be used, or those was already used during parsing.

Conclusion

Even if DOM seems more appealing becouse of object nature, really, even if more complex (local structures for data are needed), SAX is surely better for extracting all data from an XML document.

Simulare eventi dell’interfaccia

void CMyAppView::SignalImageStored()
{
       TKeyEvent aKeyEvent;
       TEventCode aType;
       aKeyEvent.iCode = EKeyMenu;
       aKeyEvent.iScanCode = EStdKeyMenu;
       aType = EEventKey;
       iCoeEnv->SimulateKeyEventL(aKeyEvent, aType);
}

iCoeEnv is a member of CAknView class, this is useful to open menu automatically, maybe after a laps of time.

… and this cause only menu event, not the corresponding key be pressed when menu is visible, so setting a timer event that cause SignalImageStored be called (i.e. from a CActive derived class) could not cause select action. There can be some problem if the view is no more visible/activated … (to be added a test on active state of this view.

Quanto spendo per una connessione gprs/umts ?

Così feci. Ma dopo un mese scopro che mi addebitano 25 euro per
traffico GPRS. Non nascondo che ero un po’ incazzato per questa
faccenda. Tra l’altro lavoravo per la Wind e giù a dirmi che non
dovevo usare Vodafone perché con Wind questo non sarebbe successo.

Beh, chiamo il centro servizi e chiedo spiegazioni. Mi fa “ha superato
il traffico telefonico limite”, e io “cosa? 500 mega? con una
connessione GPRS? guardi che sbaglia”, “no”. Ebbi a che fare con
diversi operatori (telefonisti). Le risposte erano varianti casuali.

Capitava che al tempo avessi su una Debian sul laptop .. decisi di
fare qualcosa per risolvere quest’arcano … /var/log/messages? esatto

Diedi un’occhiata col less …

Jul  3 12:34:29 fincos pppd[27733]: Sent 39566 bytes, received 415222 bytes.

No, forse è meglio “grep -e ‘pppd.*Sent’ messages|less”

4133 + 20392 + 39566 ...

… vabbè, ma non sono una calcolatrice, non io.

#!/usr/bin/perl -w

open(FILE,"<messages");

$bytes = 0;
while ($line = ) {
    if ($line =~ /pppd.*Sent\ ([0-9]+).*received\ ([0-9]+)/) {
	$bytes += $1 +$2;
    }
}

print "$bytes\n";
print $bytes/1024 ."\n";
print $bytes/1000 . "\n";
...
114166219
111490.448242188
114166.219

.. beh non si può dire che non mi sono dato da fare a scaricare .. ma
sono 114 Mega … facciamo 115. Richiamo il 190, controllo anche nel
sito 190.it …

Dopo un po’ di sbattimenti vengo a scoprire che mi avevano addebitato
il traffico fatto a Febbraio, mentre ero in treno, a navigare col
browser wap del mio Nokia 3650 (fu quello il giorno in cui scoprii il
motore wap di google)… Ma perché non l’avete detto?

Nel frattempo Fernando se ne era andato, io recuperai un modem ADSL e
lo collegai al computer, ma la connessione era a tempo, l’ADSL, e a
consumo, la GPRS. Per di più il lavoro per la wind era finito e dovevo
lavorare ad un sito web: ora la connessione era necessaria e i soldi
andavano scemando, dovevo controllare i consumi.

Mi venne in mente di far fare tutto in automatico di modo di poter
sapere quanto stavo spendendo, non superare il limite dei 500 mega
della vodafone, e limitare i costi della ADSL a tempo (che erano una
vera mazzata): la GPRS sempre attaccata, quando avevo bisogno di
scaricare avviavo l’adsl…

ppplogger versione 0.2

Decisi di usare questo programmino C che all’avvio della connessione
inseriva in un db MySQL i dati della connessione, e alla fine segnava
tutti i consumi (tempo e traffico). Il primo problema è che tale
ppplogger è un programma che era solo nella mia fantasia, quindi
dovevo scriverlo. Poi avevo bisogno di una qualche interfaccia per
fare facilmente le interrogazioni, l’avrei scritta in php, anzi, l’ho
scritta in php, ma poi mi accorsi che faceva schifo e non mi piaceva,
quindi decisi di scriverla in GTK.

Il pppd

Mi capita di sapere che sui *nix ci sono le pagine di manuale, quindi
leggendo quella del pppd vedo che posso impostare script di ip-up e di
ip-down (tipicamente nella distribuzione c’è già e chiama tutti i
programmi presenti nelle directories /etc/ppp/ip-up.d/ e
/etc/ppp/ip-down.d/), e vedo anche che tali script vengono chiamante
con delle variabili d’ambiente che riportano lo stato rispettivamente
dell’avvio e delle terminazione del demone pppd. Beh, nulla di più
banale.

Ok. Scrivo. Compilo. Le cose funzionano. L’interfaccia php fa schifo.

Il programma GTK … do’ un’occhiata al tutorial del sito gtk.org
.. questa libreria fa un po’ schifo a dir la verità … ma forse sono
un tipo difficile di natura. Provo libglade… non funziona .. segnali
non connessi .. funzioni non trovate … Ho speso un pomeriggio per
capire che quei simpaticoni della libglade le cose le scrivono tra le
righe: bisogna aggiungere -export-dynamic alle opzioni di
compilazione: `pkg-config –cflags –libs libglade-2.0` non lo fa!

Potrei usare una libreria per collegarmi al db mysql, la libgda, ma ho
già letto troppa documentazione, userò la libmysql come i comuni
mortali idioti come me.

Le cose che devo fare sono semplici:

  • connessioni ADSL
    • tempo dei consumi da giorno-ora a giorno-ora
    • costo (moltiplicare per costo a minuto o a secondo)
  • connessioni GPRS
    • traffico da giorno-ora a giorno-ora
    • costo (moltiplicare per costo a 1024 bytes o a 1000 bytes)

Deve esserci una finestra, deve esserci un selettore di connessione
(gprs, adsl .. una combo box), devono esserci 2 selettori di data-ora
(datetime picker), deve esserci due textbox per i costo e due combo
per decidere a che unità applicarlo, voglio un report totale e una
column view per la lista delle connessioni nel periodo scelto, voglio
un tasto per collegarsi al db, una finestra di dialogo per mettere i
parametri di connessione, un tasto per aggiornare la richiesta. Cioè:



Ora ho un po’ di log salvati (messages.?) vorrei parsarli e metter
dentro le connessioni effettuate nel db. Lo faccio col perl che per il
parsing va piuttosto bene.

Ok, il file reportcon.pl è in
http://repository.smartango.com/parsing_log/

Ora il resto è alla rinfusa in
http://repository.smartango.com/debian/

Ci sono i pacchetti debianizzati, sarebbe il caso di fare un
repository debian.

Home pppd-logger