/android/import-contacts

To get this branch, use:
bzr branch http://bzr.ed.am/android/import-contacts

« back to all changes in this revision

Viewing changes to src/org/waxworlds/edam/importcontacts/VcardImporter.java

  • Committer: edam
  • Date: 2011-05-30 14:04:51 UTC
  • Revision ID: edam@waxworlds.org-20110530140451-d99fy3zoi6zq1jf2
- renamed VCFImporter to VcardImporter and VCard to Vcard

Show diffs side-by-side

added added

removed removed

1
1
/*
2
2
 * VCFImporter.java
3
3
 *
4
 
 * Copyright (C) 2009 Tim Marston <edam@waxworlds.org>
 
4
 * Copyright (C) 2009 to 2011 Tim Marston <edam@waxworlds.org>
5
5
 *
6
6
 * This file is part of the Import Contacts program (hereafter referred
7
7
 * to as "this program"). For more information, see
34
34
import java.nio.ByteBuffer;
35
35
import java.util.ArrayList;
36
36
import java.util.Arrays;
 
37
import java.util.HashMap;
37
38
import java.util.HashSet;
38
39
import java.util.Iterator;
39
40
import java.util.List;
47
48
import android.provider.Contacts;
48
49
import android.provider.Contacts.PhonesColumns;
49
50
 
50
 
public class VCFImporter extends Importer
 
51
public class VcardImporter extends Importer
51
52
{
52
 
        private int _vCardCount = 0;
 
53
        private int _vcard_count = 0;
53
54
        private int _progress = 0;
54
55
 
55
 
        public VCFImporter( Doit doit )
 
56
        public VcardImporter( Doit doit )
56
57
        {
57
58
                super( doit );
58
59
        }
109
110
                        countVCardFile( files[ i ] );
110
111
                        setTmpProgress( i );
111
112
                }
112
 
                setProgressMax( _vCardCount );  // will also update tmp progress
 
113
                setProgressMax( _vcard_count ); // will also update tmp progress
113
114
 
114
115
                // import them
115
116
                setProgress( 0 );
127
128
 
128
129
                        // read
129
130
                        String line;
130
 
                        boolean inVCard = false;
 
131
                        boolean in_vcard = false;
131
132
                        while( ( line = reader.readLine() ) != null )
132
133
                        {
133
 
                                if( !inVCard ) {
 
134
                                if( !in_vcard ) {
134
135
                                        // look for vcard beginning
135
136
                                        if( line.matches( "^BEGIN:VCARD" ) ) {
136
 
                                                inVCard = true;
137
 
                                                _vCardCount++;
 
137
                                                in_vcard = true;
 
138
                                                _vcard_count++;
138
139
                                        }
139
140
                                }
140
141
                                else if( line.matches( "^END:VCARD" ) )
141
 
                                        inVCard = false;
 
142
                                        in_vcard = false;
142
143
                        }
143
144
 
144
145
                }
184
185
                throws AbortImportException
185
186
        {
186
187
                // go through lines
187
 
                VCard vCard = null;
 
188
                Vcard vcard = null;
188
189
                ContentLineIterator cli = new ContentLineIterator( content );
189
190
                while( cli.hasNext() )
190
191
                {
201
202
                                line = "";
202
203
                        }
203
204
 
204
 
                        if( vCard == null ) {
 
205
                        if( vcard == null ) {
205
206
                                // look for vcard beginning
206
207
                                if( line.matches( "^BEGIN:VCARD" ) ) {
207
208
                                        setProgress( ++_progress );
208
 
                                        vCard = new VCard();
 
209
                                        vcard = new Vcard();
209
210
                                }
210
211
                        }
211
212
                        else {
214
215
                                {
215
216
                                        // store vcard and do away with it
216
217
                                        try {
217
 
                                                vCard.finaliseParsing();
218
 
                                                importContact( vCard );
 
218
                                                vcard.finaliseParsing();
 
219
                                                importContact( vcard );
219
220
                                        }
220
 
                                        catch( VCard.ParseException e ) {
 
221
                                        catch( Vcard.ParseException e ) {
221
222
                                                skipContact();
222
223
                                                if( !showContinue(
223
224
                                                        getText( R.string.error_vcf_parse ).toString()
226
227
                                                        finish( ACTION_ABORT );
227
228
                                                }
228
229
                                        }
229
 
                                        catch( VCard.SkipContactException e ) {
 
230
                                        catch( Vcard.SkipContactException e ) {
230
231
                                                skipContact();
231
232
                                                // do nothing
232
233
                                        }
233
 
                                        vCard = null;
 
234
                                        vcard = null;
234
235
                                }
235
236
                                else
236
237
                                {
237
238
                                        // try giving the line to the vcard
238
239
                                        try {
239
 
                                                vCard.parseLine( buffer, line,
 
240
                                                vcard.parseLine( buffer, line,
240
241
                                                        cli.doesNextLineLookFolded() );
241
242
                                        }
242
 
                                        catch( VCard.ParseException e ) {
 
243
                                        catch( Vcard.ParseException e ) {
243
244
                                                skipContact();
244
245
                                                if( !showContinue(
245
246
                                                        getText( R.string.error_vcf_parse ).toString()
251
252
                                                // although we're continuing, we still need to abort
252
253
                                                // this vCard. Further lines will be ignored until we
253
254
                                                // get to another BEGIN:VCARD line.
254
 
                                                vCard = null;
 
255
                                                vcard = null;
255
256
                                        }
256
 
                                        catch( VCard.SkipContactException e ) {
 
257
                                        catch( Vcard.SkipContactException e ) {
257
258
                                                skipContact();
258
259
                                                // abort this vCard. Further lines will be ignored until
259
260
                                                // we get to another BEGIN:VCARD line.
260
 
                                                vCard = null;
 
261
                                                vcard = null;
261
262
                                        }
262
263
                                }
263
264
                        }
327
328
                }
328
329
        }
329
330
 
330
 
        private class VCard extends ContactData
 
331
        private class Vcard extends ContactData
331
332
        {
332
333
                private final static int NAMELEVEL_NONE = 0;
333
 
                private final static int NAMELEVEL_ORG = 1;
334
 
                private final static int NAMELEVEL_FN = 2;
335
 
                private final static int NAMELEVEL_N = 3;
 
334
                private final static int NAMELEVEL_FN = 1;
 
335
                private final static int NAMELEVEL_N = 2;
336
336
 
337
337
                private final static int MULTILINE_NONE = 0;
338
338
                private final static int MULTILINE_ENCODED = 1; // v2.1 quoted-printable
345
345
                private int _parser_multiline_state = MULTILINE_NONE;
346
346
                private String _parser_current_name_and_params = null;
347
347
                private String _parser_buffered_value_so_far = "";
 
348
                private String _cached_organisation = null;
 
349
                private String _cached_title = null;
348
350
 
349
351
                protected class UnencodeResult
350
352
                {
380
382
 
381
383
                        public ParseException( int res )
382
384
                        {
383
 
                                super( VCFImporter.this.getText( res ).toString() );
 
385
                                super( VcardImporter.this.getText( res ).toString() );
384
386
                        }
385
387
                }
386
388
 
621
623
                                        parseFN( name_param_parts, complete_value );
622
624
                                else if( name_param_parts[ 0 ].equals( "ORG" ) )
623
625
                                        parseORG( name_param_parts, complete_value );
 
626
                                else if( name_param_parts[ 0 ].equals( "TITLE" ) )
 
627
                                        parseTITLE( name_param_parts, complete_value );
624
628
                                else if( name_param_parts[ 0 ].equals( "TEL" ) )
625
629
                                        parseTEL( name_param_parts, complete_value );
626
630
                                else if( name_param_parts[ 0 ].equals( "EMAIL" ) )
683
687
                }
684
688
 
685
689
                private void parseN( String[] params, String value )
686
 
                        throws ParseException, SkipContactException,
687
 
                        AbortImportException
688
690
                {
689
691
                        // already got a better name?
690
692
                        if( _name_level >= NAMELEVEL_N ) return;
702
704
                        // set name
703
705
                        setName( value );
704
706
                        _name_level = NAMELEVEL_N;
705
 
 
706
 
                        // check now to see if we need to import this contact (to avoid
707
 
                        // parsing the rest of the vCard unnecessarily)
708
 
                        if( !isImportRequired( getName() ) )
709
 
                                throw new SkipContactException();
710
707
                }
711
708
 
712
709
                private void parseFN( String[] params, String value )
713
 
                        throws ParseException, SkipContactException
714
710
                {
715
711
                        // already got a better name?
716
712
                        if( _name_level >= NAMELEVEL_FN ) return;
721
717
                }
722
718
 
723
719
                private void parseORG( String[] params, String value )
724
 
                        throws ParseException, SkipContactException
725
720
                {
726
 
                        // already got a better name?
727
 
                        if( _name_level >= NAMELEVEL_ORG ) return;
728
 
 
729
721
                        // get org parts
730
722
                        String[] org_parts = splitValueBySemicolon( value );
731
 
 
732
 
                        // build name
733
 
                        if( org_parts.length > 1 && org_parts[ 0 ].length() == 0 )
734
 
                                value = org_parts[ 1 ];
735
 
                        else if( org_parts.length > 1 && org_parts[ 1 ].length() > 0 )
736
 
                                value = org_parts[ 0 ] + ", " + org_parts[ 1 ];
737
 
                        else
738
 
                                value = org_parts[ 0 ];
739
 
 
740
 
                        // set name
741
 
                        setName( value );
742
 
                        _name_level = NAMELEVEL_ORG;
 
723
                        if( org_parts == null || org_parts.length < 1 ) return;
 
724
 
 
725
                        // build organisation name
 
726
                        StringBuilder builder = new StringBuilder(
 
727
                                String.valueOf( org_parts[ 0 ] ) );
 
728
                        for( int a = 1; a < org_parts.length; a++ )
 
729
                                builder.append( ", " ).append( org_parts[ a ] );
 
730
                        String organisation = builder.toString();
 
731
 
 
732
                        // set organisation name (using a title we've previously found)
 
733
                        addOrganisation( organisation, _cached_title, true );
 
734
 
 
735
                        // if we've not previously found a title, store this organisation
 
736
                        // name (we'll need it when we find a title to update the
 
737
                        // organisation, by name), else if we *have* previously found a
 
738
                        // title, clear it (since we just used it)
 
739
                        if( _cached_title == null )
 
740
                                _cached_organisation = organisation;
 
741
                        else
 
742
                                _cached_title = null;
 
743
                }
 
744
 
 
745
                private void parseTITLE( String[] params, String value )
 
746
                {
 
747
                        // if we previously had an organisation, look it up and append this
 
748
                        // title to it
 
749
                        if( _cached_organisation != null && hasOrganisations() ) {
 
750
                                HashMap< String, ExtraDetail > datas = getOrganisations();
 
751
                                ExtraDetail detail = datas.get( _cached_organisation );
 
752
                                if( detail != null )
 
753
                                        detail.setExtra( value );
 
754
                        }
 
755
 
 
756
                        // same as when handling organisation, if we've not previously found
 
757
                        // an organisation we store this title, else we clear it (since we
 
758
                        // just appended this title to it)
 
759
                        if( _cached_organisation == null )
 
760
                                _cached_title = value;
 
761
                        else
 
762
                                _cached_organisation = null;
743
763
                }
744
764
 
745
765
                private void parseTEL( String[] params, String value )
746
 
                        throws ParseException
747
766
                {
748
767
                        if( value.length() == 0 ) return;
749
768
 
752
771
                                "PAGER", "BBS", "MODEM", "CAR", "ISDN", "VIDEO" ) );
753
772
 
754
773
                        // here's the logic...
755
 
                        boolean preferred = types.contains( "PREF" );
756
 
                        int type = PhonesColumns.TYPE_MOBILE;
757
 
                        if( types.contains( "VOICE" ) )
758
 
                                if( types.contains( "WORK" ) )
759
 
                                        type = PhonesColumns.TYPE_WORK;
760
 
                                else
761
 
                                        type = PhonesColumns.TYPE_HOME;
762
 
                        else if( types.contains( "CELL" ) || types.contains( "VIDEO" ) )
763
 
                                type = PhonesColumns.TYPE_MOBILE;
 
774
                        boolean is_preferred = types.contains( "PREF" );
 
775
                        int type;
764
776
                        if( types.contains( "FAX" ) )
765
777
                                if( types.contains( "HOME" ) )
766
778
                                        type = PhonesColumns.TYPE_FAX_HOME;
767
779
                                else
768
780
                                        type = PhonesColumns.TYPE_FAX_WORK;
769
 
                        if( types.contains( "PAGER" ) )
 
781
                        else if( types.contains( "CELL" ) || types.contains( "VIDEO" ) )
 
782
                                type = PhonesColumns.TYPE_MOBILE;
 
783
                        else if( types.contains( "PAGER" ) )
770
784
                                type = PhonesColumns.TYPE_PAGER;
 
785
                        else if( types.contains( "WORK" ) )
 
786
                                type = PhonesColumns.TYPE_WORK;
 
787
                        else
 
788
                                type = PhonesColumns.TYPE_HOME;
771
789
 
772
790
                        // add phone number
773
 
                        addPhone( value, type, preferred );
 
791
                        addNumber( value, type, is_preferred );
774
792
                }
775
793
 
776
794
                public void parseEMAIL( String[] params, String value )
777
 
                        throws ParseException
778
795
                {
779
796
                        if( value.length() == 0 ) return;
780
797
 
782
799
                                "PREF", "WORK", "HOME", "INTERNET" ) );
783
800
 
784
801
                        // add email address
785
 
                        boolean preferred = types.contains( "PREF" );
 
802
                        boolean is_preferred = types.contains( "PREF" );
 
803
                        int type;
786
804
                        if( types.contains( "WORK" ) )
787
 
                                addEmail( value, Contacts.ContactMethods.TYPE_WORK, preferred );
 
805
                                type = Contacts.ContactMethods.TYPE_WORK;
788
806
                        else
789
 
                                addEmail( value, Contacts.ContactMethods.TYPE_HOME, preferred );
 
807
                                type = Contacts.ContactMethods.TYPE_HOME;
 
808
 
 
809
                        addEmail( value, type, is_preferred );
790
810
                }
791
811
 
792
812
                private void parseADR( String[] params, String value )
793
 
                        throws ParseException, SkipContactException
794
813
                {
795
814
                        // get address parts
796
815
                        String[] adr_parts = splitValueBySemicolon( value );
806
825
                                "PREF", "WORK", "HOME", "INTERNET" ) );
807
826
 
808
827
                        // add address
 
828
                        int type;
809
829
                        if( types.contains( "WORK" ) )
810
 
                                addAddress( value, Contacts.ContactMethods.TYPE_WORK );
 
830
                                type = Contacts.ContactMethods.TYPE_WORK;
811
831
                        else
812
 
                                addAddress( value, Contacts.ContactMethods.TYPE_HOME);
 
832
                                type = Contacts.ContactMethods.TYPE_HOME;
 
833
 
 
834
                        addAddress( value, type );
813
835
                }
814
836
 
815
837
                public void finaliseParsing()
820
842
                        if( _version == null && _buffers != null )
821
843
                                throw new ParseException( R.string.error_vcf_malformed );
822
844
 
823
 
                        //  missing name properties?
824
 
                        if( _name_level == NAMELEVEL_NONE )
825
 
                                throw new ParseException( R.string.error_vcf_noname );
826
 
 
827
 
                        // check if we should import this one? If we've already got an 'N'-
828
 
                        // type name, this will already have been done by parseN() so we
829
 
                        // mustn't do this here (or it could prompt twice!)
830
 
                        if( _name_level < NAMELEVEL_N && !isImportRequired( getName() ) )
831
 
                                throw new SkipContactException();
 
845
                        // check if we should import this contact
 
846
                        try {
 
847
                                if( !isImportRequired( this ) )
 
848
                                        throw new SkipContactException();
 
849
                        }
 
850
                        catch( ContactNeedsMoreInfoException e ) {
 
851
                                throw new ParseException( R.string.error_vcf_notenoughinfo );
 
852
                        }
832
853
                }
833
854
 
834
855
                private String checkParam( String[] params, String name )