• Come un abito cucito su misura, i nostri progetti software uniscono le potenzialità di tecnologie innovative alle specifiche esigenze del cliente.

    Showcase progetti
  • Analizziamo e razionalizziamo con il cliente i processi e le attività della propria azienda, per poi seguirlo nella scelta delle giuste strategie IT da adottare.

    Le nostre competenze
  • Crediamo nelle potenzialità di un percorso formativo che unisca forti basi teoriche e metodologiche ad una continua applicazione pratica di quanto si apprende.

    Dettaglio dei corsi
  • Progettiamo e sviluppiamo sistemi e progetti basati su dispositivi mobile consumer (iPhone, Windows Phone 7 Series), industriali (Windows CE) e custom (basati su microcontrollori 8/16/32 bit).

    Approfondimenti
 

Esportare gli sms di iPhone con Entity Framework, SQLite e FileHelpers

March 31, 2010 11:13 by M.Poponi

Domenica scorsa ho avuto bisogno di esportare in un file gli SMS presenti nel mio fido iPhone. "Niente di più semplice", ho pensato, abituato alla Nokia PCSuite, "ci sarà una comoda funzione di iTunes che lo fa".

Errore.

iTunes non permette di esportare gli SMS presenti nell'iPhone! cercando un po' su google, ho trovato una schiera di programmi non free che lo fanno, addirittura alcuni siti che lo fanno online, entrambe le soluzione inaccettabili: non ho voglia di spendere soldi per una funzione che dovrebbe essere fornita gratuitamente e non ho voglia di uploadare i miei SMS personali su un sito che non conosco. Mi sono un po' documentato, ho scoperto qualcosa di utile e ne è uscita fuori un'applicazioncina che esporta gli sms e un'esperienza didatticamente interessante.
Ecco come ho fatto.
Premessa: Non è possibile estrarre gli SMS direttamente da un iPhone (legalmente). Quel che si deve fare è passare per il backup di iTunes.

I passi:

1) backuppare l'iphone con iTunes

2) andare sulla cartella %appdata%\Apple Computer\MobileSync\Backup\

3) c'è una sola cartella qui dentro, chiamata con un numero GUID-like. esplorare questa cartella, e individuare due files: 3d0d7e5fb2ce288813306e4d4636395e047a3d28.mddata è un db SQLite che contiene gli SMS 31bb7ba8914766d4ba40d6dfb6113c8b614be442.mddata è un db SQLite che contiene i contatti

4) utilizzare un qualche strumento SQLite che permette di leggere i db. Vi consiglio http://code.google.com/p/sqlite-manager/, una utilissima estensione per FireFox.

Il primo DB ha una tabella, message, che contiene i veri e propri SMS. La struttura di tale tabella è:

 messages

i campi più interessanti sono:

address: contiene il numero di telefono da cui/ verso il quale è stato inviato l'sms
date: timestamp UNIX della data di invio
flags: 2 se è un SMS in ingresso, 3 se è un SMS in uscita
text: il testo del messaggio

5) se invece dei numeri di telefono vogliamo sapere il nome dei contatti con cui abbiamo scambiato gli sms, occorre aprire l'altro DB. questo basterebbe per esportare gli SMS. contacts

 

In ABPerson troviamo tutti i nostri contatti, in ABMultivalue i numeri di telefono (e altre info), facendo la join ABMultivalue.record_id=ABPerson.ROWID.

 

Tra l'altro lo stesso sqlite manager può esportare i dati contenuti nella tabella, ma noi siamo sviluppatori, quindi facciamo un'applicazioncina! 

 

Strumenti:

1) volendo utilizzare per l’accesso ai dati Entity Framework, ho dovuto cercare un provider di accesso a SQLite che lo supportasse.  La scelta è caduta su System.Data.SQLite: http://sqlite.phxsoftware.com/ 

2) volendo esportare i dati, ho optato per un vecchio amore che mi ha fatto risparmiare innumerevoli ore di lavoro negli anni: FileHelpers

L’applicazione:

La realizzazione dell’applicazione è stata davvero istantanea:

1) Ho installato System.Data.SQLite

2) Ho creato un’applicazione Winforms, aggiunto i riferimenti a System.Data.SQLite, System.Data.SQLite.Linq e FileHelpers

3) Ho aggiunto al server explorer due connessioni di tipo SQLite ai due files/db di cui abbiamo parlato sopra

4) Ho creato due modelli di Entity Framework: Entities che contiene le tabelle relative agli SMS e Contacts che contiene, be’… lo avete capito.

5) Nella form principale ho aggiunto una lista che conterrà i contatti (lbContacts), un Menu per le funzionalità di esportazione, una DataGridView per contenere i messaggi.

6) Ho scritto una classe per trasportare i dati dei contatti:

   1: public class PersonDTO
   2:   {
   3:       public string Person { get; set; }
   4:        
   5:       public string Address{ get; set; }
   6:       
   7:   }

7) Una semplice funzioncina che all’avvio carica i dati dei contatti che hanno SMS, ripulisce i numeri di telefono da ‘+’ e spazi, estrae i nomi e li mette nella ListBox:

   1: public void LoadAddressess()
   2:        {
   3:            Entities ent  = new Entities();
   4:            var addresses = (from  m in ent.message select  new {address= m.address.Replace(" ","").Replace("+","")}).Distinct();
   5:  
   6:            Contacts cont = new Contacts();
   7:            var numbersContacts = from d in cont.ABPerson
   8:                                  join v in cont.ABMultiValue on d.ROWID equals v.record_id
   9:                                   select new {person = (d.First??"") + " " + (d.Last??""), number = v.value.Replace(" ","").Replace("+","")};
  10:  
  11:                              
  12:  
  13:            var smartAddresses= from nc in numbersContacts.ToList() join m in addresses.ToList()
  14:                                                           on nc.number equals m.address
  15:                                                           select new PersonDTO() {Person=nc.person , Address=m.address}
  16:            ;
  17:            lbAddresses.DisplayMember = "Person";
  18:            lbAddresses.DataSource = smartAddresses.ToList();
  19:             
  20:        }
  21:        private void Form1_Load(object sender, EventArgs e)
  22:        {
  23:            LoadAddressess();
  24:  
  25:  
  26:        }

 

8) Ho creato un DTO per contenere gli SMS:

   1: [FileHelpers.DelimitedRecord("|")]
   2:    public class SMSDTO
   3:    {
   4:        private string numero;
   5:        private string inOut;
   6:        [FileHelpers.FieldConverter(FileHelpers.ConverterKind.Date,"dd-MM-yyyy HH:mm:ss")]
   7:       
   8:        private DateTime dataOra;
   9:        private String testo;
  10:       
  11:    public string Numero
  12:        {
  13:            get { return numero; }
  14:            set { numero = value; }
  15:        }
  16:        public DateTime DataOra
  17:        {
  18:            get
  19:            {
  20:                return dataOra;
  21:            }
  22:            set { dataOra = value; }
  23:        }
  24:  
  25:        public string Testo
  26:        {
  27:            get { return testo; }
  28:            set { testo = value; }
  29:        }
  30:  
  31:        public string InOut
  32:        {
  33:            get { return inOut; }
  34:            set { inOut = value; }
  35:        }
  36:  
  37:       
  38:    }

 

Tanto che c’ero :) ho aggiunto due attirbuti che dicono a FileHelpers che voglio esportare i dati in un file a campi delimitati dal pipe (‘|’) e che voglio che la data sia nel formato italiano.

 

9) A questo punto è banale scrivere una funzioncina che ottiene gli SMS relativi al numero selezionato nella lista, e una che invece ottiene tutti gli SMS

   1: public IEnumerable<SMSDTO> GetSelectedSms()
   2:         {
   3:             Entities ent = new Entities();
   4:             string address = ((PersonDTO) lbAddresses.SelectedItem).Address;
   5:             var messages = (from m in ent.message where m.address.Replace(" ", "").Replace("+", "") == address select new {m.address, m.date, m.text, m.flags });
   6:  
   7:             return from m in messages.ToList()
   8:                    select
   9:                        new SMSDTO()
  10:                            {
  11:                                Numero =m.address,
  12:                                DataOra   = ConvertTimestamp((double) m.date),
  13:                                Testo = m.text,
  14:                                InOut = m.flags == 2 ? "in " : "out"
  15:                            };
  16:         }
  17:         public IEnumerable<SMSDTO> GetAllSms()
  18:         {
  19:             Entities ent = new Entities();
  20:             
  21:             var messages = (from m in ent.message  select new { m.address, m.date, m.text, m.flags });
  22:  
  23:             return from m in messages.ToList()
  24:                    select
  25:                        new SMSDTO()
  26:                        {
  27:                            Numero = m.address,
  28:                            DataOra = ConvertTimestamp((double)m.date),
  29:                            Testo = m.text,
  30:                            InOut = m.flags == 2 ? "in " : "out"
  31:                        };
  32:         }

le date devono essere convertite da Unix ad un formato più maneggevole, per questo basta una funzioncina semplice semplice:

   1: private static DateTime ConvertTimestamp(double timestamp)
   2:   
   3:      {
   4:   
   5:          return (new DateTime(1970, 1, 1, 0, 0, 0, 0)).AddSeconds(timestamp).ToLocalTime();
   6:  
   7:      } 

10) A questo punto basta solo collegare il binding della DataGridView al cambio di selezione della lista per vedere i dati,

   1: private void lbAddresses_SelectedIndexChanged(object sender, EventArgs e)
   2:       {
   3:           IEnumerable<SMSDTO> SMS = GetSelectedSms();
   4:  
   5:           dgvMessages.DataSource = SMS.ToList();
   6:       }

e collegare il click di due voci di menu per esportare i dati selezionati o tutti i dati in un file, con l’incredibile FileHelpers:

   1: private void exportSelectedToolStripMenuItem_Click(object sender, EventArgs e)
   2:        {
   3:            ExportSMS( GetSelectedSms()  );
   4:        }
   5:        private void exportAllToolStripMenuItem_Click(object sender, EventArgs e)
   6:        {
   7:            ExportSMS(GetAllSms());
   8:        }
   9:  
  10:  
  11:        private void ExportSMS(IEnumerable records)
  12:        {
  13:            FileHelpers.DelimitedFileEngine engine = new DelimitedFileEngine(typeof(SMSDTO));
  14:            SaveFileDialog sfd= new SaveFileDialog();
  15:            sfd.DefaultExt = ".csv";
  16:            sfd.FileName = "export.csv";
  17:            if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
  18:            { 
  19:                engine.WriteFile(sfd.FileName,records);
  20:            }
  21:        }

e abbiamo finito!

Conclusioni:

Abbiamo visto come sia possibile utilizzare Entity Framework con SQLite in modo semplice ed efficace, come l’esportazione su file sia immediata con FileHelpers e come questo possa essere utilizzato per l’esportazione dei propri SMS da un backup iPhone.

Buon divertimento!!!


Currently rated 4.7 by 3 people

  • Currently 4.666667/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5