/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/VCFImporter.java

  • Committer: edam
  • Date: 2011-04-22 15:36:06 UTC
  • Revision ID: edam@waxworlds.org-20110422153606-9x9l0nbmvx6oxfxu
- pulled contacts cache out in to seperate class

Show diffs side-by-side

added added

removed removed

1
1
/*
2
2
 * VCFImporter.java
3
3
 *
4
 
 * Copyright (C) 2009 to 2011 Tim Marston <edam@waxworlds.org>
 
4
 * Copyright (C) 2009 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;
38
37
import java.util.HashSet;
39
38
import java.util.Iterator;
40
39
import java.util.List;
50
49
 
51
50
public class VCFImporter extends Importer
52
51
{
53
 
        private int _vcard_count = 0;
 
52
        private int _vCardCount = 0;
54
53
        private int _progress = 0;
55
54
 
56
55
        public VCFImporter( Doit doit )
110
109
                        countVCardFile( files[ i ] );
111
110
                        setTmpProgress( i );
112
111
                }
113
 
                setProgressMax( _vcard_count ); // will also update tmp progress
 
112
                setProgressMax( _vCardCount );  // will also update tmp progress
114
113
 
115
114
                // import them
116
115
                setProgress( 0 );
128
127
 
129
128
                        // read
130
129
                        String line;
131
 
                        boolean in_vcard = false;
 
130
                        boolean inVCard = false;
132
131
                        while( ( line = reader.readLine() ) != null )
133
132
                        {
134
 
                                if( !in_vcard ) {
 
133
                                if( !inVCard ) {
135
134
                                        // look for vcard beginning
136
135
                                        if( line.matches( "^BEGIN:VCARD" ) ) {
137
 
                                                in_vcard = true;
138
 
                                                _vcard_count++;
 
136
                                                inVCard = true;
 
137
                                                _vCardCount++;
139
138
                                        }
140
139
                                }
141
140
                                else if( line.matches( "^END:VCARD" ) )
142
 
                                        in_vcard = false;
 
141
                                        inVCard = false;
143
142
                        }
144
143
 
145
144
                }
185
184
                throws AbortImportException
186
185
        {
187
186
                // go through lines
188
 
                VCard vcard = null;
 
187
                VCard vCard = null;
189
188
                ContentLineIterator cli = new ContentLineIterator( content );
190
189
                while( cli.hasNext() )
191
190
                {
202
201
                                line = "";
203
202
                        }
204
203
 
205
 
                        if( vcard == null ) {
 
204
                        if( vCard == null ) {
206
205
                                // look for vcard beginning
207
206
                                if( line.matches( "^BEGIN:VCARD" ) ) {
208
207
                                        setProgress( ++_progress );
209
 
                                        vcard = new VCard();
 
208
                                        vCard = new VCard();
210
209
                                }
211
210
                        }
212
211
                        else {
215
214
                                {
216
215
                                        // store vcard and do away with it
217
216
                                        try {
218
 
                                                vcard.finaliseParsing();
219
 
                                                importContact( vcard );
 
217
                                                vCard.finaliseParsing();
 
218
                                                importContact( vCard );
220
219
                                        }
221
220
                                        catch( VCard.ParseException e ) {
222
221
                                                skipContact();
231
230
                                                skipContact();
232
231
                                                // do nothing
233
232
                                        }
234
 
                                        vcard = null;
 
233
                                        vCard = null;
235
234
                                }
236
235
                                else
237
236
                                {
238
237
                                        // try giving the line to the vcard
239
238
                                        try {
240
 
                                                vcard.parseLine( buffer, line,
 
239
                                                vCard.parseLine( buffer, line,
241
240
                                                        cli.doesNextLineLookFolded() );
242
241
                                        }
243
242
                                        catch( VCard.ParseException e ) {
252
251
                                                // although we're continuing, we still need to abort
253
252
                                                // this vCard. Further lines will be ignored until we
254
253
                                                // get to another BEGIN:VCARD line.
255
 
                                                vcard = null;
 
254
                                                vCard = null;
256
255
                                        }
257
256
                                        catch( VCard.SkipContactException e ) {
258
257
                                                skipContact();
259
258
                                                // abort this vCard. Further lines will be ignored until
260
259
                                                // we get to another BEGIN:VCARD line.
261
 
                                                vcard = null;
 
260
                                                vCard = null;
262
261
                                        }
263
262
                                }
264
263
                        }
331
330
        private class VCard extends ContactData
332
331
        {
333
332
                private final static int NAMELEVEL_NONE = 0;
334
 
                private final static int NAMELEVEL_FN = 1;
335
 
                private final static int NAMELEVEL_N = 2;
 
333
                private final static int NAMELEVEL_ORG = 1;
 
334
                private final static int NAMELEVEL_FN = 2;
 
335
                private final static int NAMELEVEL_N = 3;
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;
350
348
 
351
349
                protected class UnencodeResult
352
350
                {
623
621
                                        parseFN( name_param_parts, complete_value );
624
622
                                else if( name_param_parts[ 0 ].equals( "ORG" ) )
625
623
                                        parseORG( name_param_parts, complete_value );
626
 
                                else if( name_param_parts[ 0 ].equals( "TITLE" ) )
627
 
                                        parseTITLE( name_param_parts, complete_value );
628
624
                                else if( name_param_parts[ 0 ].equals( "TEL" ) )
629
625
                                        parseTEL( name_param_parts, complete_value );
630
626
                                else if( name_param_parts[ 0 ].equals( "EMAIL" ) )
687
683
                }
688
684
 
689
685
                private void parseN( String[] params, String value )
 
686
                        throws ParseException, SkipContactException,
 
687
                        AbortImportException
690
688
                {
691
689
                        // already got a better name?
692
690
                        if( _name_level >= NAMELEVEL_N ) return;
704
702
                        // set name
705
703
                        setName( value );
706
704
                        _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();
707
710
                }
708
711
 
709
712
                private void parseFN( String[] params, String value )
 
713
                        throws ParseException, SkipContactException
710
714
                {
711
715
                        // already got a better name?
712
716
                        if( _name_level >= NAMELEVEL_FN ) return;
717
721
                }
718
722
 
719
723
                private void parseORG( String[] params, String value )
 
724
                        throws ParseException, SkipContactException
720
725
                {
 
726
                        // already got a better name?
 
727
                        if( _name_level >= NAMELEVEL_ORG ) return;
 
728
 
721
729
                        // get org parts
722
730
                        String[] org_parts = splitValueBySemicolon( value );
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;
 
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;
763
743
                }
764
744
 
765
745
                private void parseTEL( String[] params, String value )
 
746
                        throws ParseException
766
747
                {
767
748
                        if( value.length() == 0 ) return;
768
749
 
771
752
                                "PAGER", "BBS", "MODEM", "CAR", "ISDN", "VIDEO" ) );
772
753
 
773
754
                        // here's the logic...
774
 
                        boolean is_preferred = types.contains( "PREF" );
775
 
                        int type;
 
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;
776
764
                        if( types.contains( "FAX" ) )
777
765
                                if( types.contains( "HOME" ) )
778
766
                                        type = PhonesColumns.TYPE_FAX_HOME;
779
767
                                else
780
768
                                        type = PhonesColumns.TYPE_FAX_WORK;
781
 
                        else if( types.contains( "CELL" ) || types.contains( "VIDEO" ) )
782
 
                                type = PhonesColumns.TYPE_MOBILE;
783
 
                        else if( types.contains( "PAGER" ) )
 
769
                        if( types.contains( "PAGER" ) )
784
770
                                type = PhonesColumns.TYPE_PAGER;
785
 
                        else if( types.contains( "WORK" ) )
786
 
                                type = PhonesColumns.TYPE_WORK;
787
 
                        else
788
 
                                type = PhonesColumns.TYPE_HOME;
789
771
 
790
772
                        // add phone number
791
 
                        addNumber( value, type, is_preferred );
 
773
                        addPhone( value, type, preferred );
792
774
                }
793
775
 
794
776
                public void parseEMAIL( String[] params, String value )
 
777
                        throws ParseException
795
778
                {
796
779
                        if( value.length() == 0 ) return;
797
780
 
799
782
                                "PREF", "WORK", "HOME", "INTERNET" ) );
800
783
 
801
784
                        // add email address
802
 
                        boolean is_preferred = types.contains( "PREF" );
803
 
                        int type;
 
785
                        boolean preferred = types.contains( "PREF" );
804
786
                        if( types.contains( "WORK" ) )
805
 
                                type = Contacts.ContactMethods.TYPE_WORK;
 
787
                                addEmail( value, Contacts.ContactMethods.TYPE_WORK, preferred );
806
788
                        else
807
 
                                type = Contacts.ContactMethods.TYPE_HOME;
808
 
 
809
 
                        addEmail( value, type, is_preferred );
 
789
                                addEmail( value, Contacts.ContactMethods.TYPE_HOME, preferred );
810
790
                }
811
791
 
812
792
                private void parseADR( String[] params, String value )
 
793
                        throws ParseException, SkipContactException
813
794
                {
814
795
                        // get address parts
815
796
                        String[] adr_parts = splitValueBySemicolon( value );
825
806
                                "PREF", "WORK", "HOME", "INTERNET" ) );
826
807
 
827
808
                        // add address
828
 
                        int type;
829
809
                        if( types.contains( "WORK" ) )
830
 
                                type = Contacts.ContactMethods.TYPE_WORK;
 
810
                                addAddress( value, Contacts.ContactMethods.TYPE_WORK );
831
811
                        else
832
 
                                type = Contacts.ContactMethods.TYPE_HOME;
833
 
 
834
 
                        addAddress( value, type );
 
812
                                addAddress( value, Contacts.ContactMethods.TYPE_HOME);
835
813
                }
836
814
 
837
815
                public void finaliseParsing()
842
820
                        if( _version == null && _buffers != null )
843
821
                                throw new ParseException( R.string.error_vcf_malformed );
844
822
 
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
 
                        }
 
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();
853
832
                }
854
833
 
855
834
                private String checkParam( String[] params, String name )