diff options
Diffstat (limited to 'src/net/java/sip/communicator/plugin/thunderbird')
-rw-r--r-- | src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdActivator.java | 336 | ||||
-rw-r--r-- | src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdContactQuery.java | 530 |
2 files changed, 433 insertions, 433 deletions
diff --git a/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdActivator.java b/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdActivator.java index 2a1bbe3..00c204e 100644 --- a/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdActivator.java +++ b/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdActivator.java @@ -1,4 +1,4 @@ -/*
+/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd @@ -15,170 +15,170 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.java.sip.communicator.plugin.thunderbird;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.contactsource.*;
-import net.java.sip.communicator.service.gui.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-import org.jitsi.service.configuration.*;
-import org.jitsi.service.resources.*;
-import org.osgi.framework.*;
-
-/**
- * Bundle-Activator for the Thunderbird address book contact source plug-in.
- *
- * @author Ingo Bauersachs
- */
-public class ThunderbirdActivator
- implements BundleActivator
-{
- /** OSGi context. */
- private static BundleContext bundleContext;
-
- /** Active address book registrations. */
- private static Map<ThunderbirdContactSourceService, ServiceRegistration>
- registrations;
-
- /**
- * The registered PhoneNumberI18nService.
- */
- private static PhoneNumberI18nService phoneNumberI18nService;
-
- /**
- * Gets the configuration service.
- * @return the configuration service.
- */
- static ConfigurationService getConfigService()
- {
- return ServiceUtils.getService(bundleContext,
- ConfigurationService.class);
- }
-
- /**
- * Gets the resource service.
- * @return the resource service.
- */
- static ResourceManagementService getResources()
- {
- return ServiceUtils.getService(bundleContext,
- ResourceManagementService.class);
- }
-
- /**
- * Gets all registered Thunderbird address book services.
- * @return all registered Thunderbird address book services.
- */
- static List<ThunderbirdContactSourceService> getActiveServices()
- {
- return new LinkedList<ThunderbirdContactSourceService>(
- registrations.keySet());
- }
-
- /**
- * Loads and registers an address book service.
- * @param config the name of the base property of the service to load.
- */
- static void add(String config)
- {
- ThunderbirdContactSourceService service
- = new ThunderbirdContactSourceService(config);
- registrations.put(service,
- bundleContext.registerService(
- ContactSourceService.class.getName(), service, null));
- }
-
- /**
- * Stops an address book service and deletes the corresponding configuration
- * data.
- *
- * @param service the address book instance to remove.
- */
- static void remove(ThunderbirdContactSourceService service)
- {
- registrations.get(service).unregister();
- registrations.remove(service);
- ConfigurationService config = getConfigService();
- config.removeProperty(service.getBaseConfigProperty());
- for (String prop : config.getPropertyNamesByPrefix(
- service.getBaseConfigProperty(), false))
- {
- config.removeProperty(prop);
- }
- }
-
- /**
- * Searches the configuration for Thunderbird address books and registers a
- * {@link ContactSourceService} for each found config.
- */
- public void start(BundleContext bundleContext) throws Exception
- {
- ThunderbirdActivator.bundleContext = bundleContext;
-
- ConfigurationService config = getConfigService();
- List<String> configs =
- config.getPropertyNamesByPrefix(
- ThunderbirdContactSourceService.PNAME_BASE_THUNDERBIRD_CONFIG,
- false);
-
- registrations = new HashMap
- <ThunderbirdContactSourceService, ServiceRegistration>();
- for (String cfg : configs)
- {
- String value = config.getString(cfg);
- if (value != null && cfg.endsWith(value))
- {
- add(cfg);
- }
- }
-
- /* registers the configuration form */
- Dictionary<String, String> properties
- = new Hashtable<String, String>();
- properties.put(
- ConfigurationForm.FORM_TYPE,
- ConfigurationForm.CONTACT_SOURCE_TYPE);
-
- bundleContext.registerService(
- ConfigurationForm.class.getName(),
- new LazyConfigurationForm(
- ThunderbirdConfigForm.class.getName(),
- getClass().getClassLoader(),
- null,
- "plugin.thunderbird.CONFIG_FORM_TITLE"),
- properties);
- }
-
- /**
- * Unregisters all {@link ContactSourceService}s that were registered by
- * this activator.
- */
- public void stop(BundleContext bundleContext) throws Exception
- {
- for (ServiceRegistration sr : registrations.values())
- {
- sr.unregister();
- }
-
- registrations = null;
- }
-
- /**
- * Returns the PhoneNumberI18nService.
- * @return returns the PhoneNumberI18nService.
- */
- public static PhoneNumberI18nService getPhoneNumberI18nService()
- {
- if(phoneNumberI18nService == null)
- {
- phoneNumberI18nService = ServiceUtils.getService(
- bundleContext,
- PhoneNumberI18nService.class);
- }
-
- return phoneNumberI18nService;
- }
-}
+package net.java.sip.communicator.plugin.thunderbird; + +import java.util.*; + +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; + +import org.jitsi.service.configuration.*; +import org.jitsi.service.resources.*; +import org.osgi.framework.*; + +/** + * Bundle-Activator for the Thunderbird address book contact source plug-in. + * + * @author Ingo Bauersachs + */ +public class ThunderbirdActivator + implements BundleActivator +{ + /** OSGi context. */ + private static BundleContext bundleContext; + + /** Active address book registrations. */ + private static Map<ThunderbirdContactSourceService, ServiceRegistration> + registrations; + + /** + * The registered PhoneNumberI18nService. + */ + private static PhoneNumberI18nService phoneNumberI18nService; + + /** + * Gets the configuration service. + * @return the configuration service. + */ + static ConfigurationService getConfigService() + { + return ServiceUtils.getService(bundleContext, + ConfigurationService.class); + } + + /** + * Gets the resource service. + * @return the resource service. + */ + static ResourceManagementService getResources() + { + return ServiceUtils.getService(bundleContext, + ResourceManagementService.class); + } + + /** + * Gets all registered Thunderbird address book services. + * @return all registered Thunderbird address book services. + */ + static List<ThunderbirdContactSourceService> getActiveServices() + { + return new LinkedList<ThunderbirdContactSourceService>( + registrations.keySet()); + } + + /** + * Loads and registers an address book service. + * @param config the name of the base property of the service to load. + */ + static void add(String config) + { + ThunderbirdContactSourceService service + = new ThunderbirdContactSourceService(config); + registrations.put(service, + bundleContext.registerService( + ContactSourceService.class.getName(), service, null)); + } + + /** + * Stops an address book service and deletes the corresponding configuration + * data. + * + * @param service the address book instance to remove. + */ + static void remove(ThunderbirdContactSourceService service) + { + registrations.get(service).unregister(); + registrations.remove(service); + ConfigurationService config = getConfigService(); + config.removeProperty(service.getBaseConfigProperty()); + for (String prop : config.getPropertyNamesByPrefix( + service.getBaseConfigProperty(), false)) + { + config.removeProperty(prop); + } + } + + /** + * Searches the configuration for Thunderbird address books and registers a + * {@link ContactSourceService} for each found config. + */ + public void start(BundleContext bundleContext) throws Exception + { + ThunderbirdActivator.bundleContext = bundleContext; + + ConfigurationService config = getConfigService(); + List<String> configs = + config.getPropertyNamesByPrefix( + ThunderbirdContactSourceService.PNAME_BASE_THUNDERBIRD_CONFIG, + false); + + registrations = new HashMap + <ThunderbirdContactSourceService, ServiceRegistration>(); + for (String cfg : configs) + { + String value = config.getString(cfg); + if (value != null && cfg.endsWith(value)) + { + add(cfg); + } + } + + /* registers the configuration form */ + Dictionary<String, String> properties + = new Hashtable<String, String>(); + properties.put( + ConfigurationForm.FORM_TYPE, + ConfigurationForm.CONTACT_SOURCE_TYPE); + + bundleContext.registerService( + ConfigurationForm.class.getName(), + new LazyConfigurationForm( + ThunderbirdConfigForm.class.getName(), + getClass().getClassLoader(), + null, + "plugin.thunderbird.CONFIG_FORM_TITLE"), + properties); + } + + /** + * Unregisters all {@link ContactSourceService}s that were registered by + * this activator. + */ + public void stop(BundleContext bundleContext) throws Exception + { + for (ServiceRegistration sr : registrations.values()) + { + sr.unregister(); + } + + registrations = null; + } + + /** + * Returns the PhoneNumberI18nService. + * @return returns the PhoneNumberI18nService. + */ + public static PhoneNumberI18nService getPhoneNumberI18nService() + { + if(phoneNumberI18nService == null) + { + phoneNumberI18nService = ServiceUtils.getService( + bundleContext, + PhoneNumberI18nService.class); + } + + return phoneNumberI18nService; + } +} diff --git a/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdContactQuery.java b/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdContactQuery.java index 429ff6c..00488f9 100644 --- a/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdContactQuery.java +++ b/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdContactQuery.java @@ -1,4 +1,4 @@ -/*
+/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd @@ -15,267 +15,267 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package net.java.sip.communicator.plugin.thunderbird;
-
-import java.io.*;
-import java.util.*;
-import java.util.Map.Entry;
-import java.util.regex.*;
-
-import org.jitsi.util.StringUtils;
-
-import mork.*;
-import net.java.sip.communicator.service.contactsource.*;
-import net.java.sip.communicator.service.contactsource.ContactDetail.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * Queries a Thunderbird address book for contacts matching the given pattern.
- *
- * @author Ingo Bauersachs
- */
-public class ThunderbirdContactQuery
- extends AsyncContactQuery<ThunderbirdContactSourceService>
-{
- /** Class logger */
- private final static Logger logger = Logger
- .getLogger(ThunderbirdContactQuery.class);
-
- /**
- * Creates a new instance of this class.
- *
- * @param owner The contact source that created this query.
- * @param query The pattern to match against the contacts database.
- */
- public ThunderbirdContactQuery(ThunderbirdContactSourceService owner,
- Pattern query)
- {
- super(owner, query);
- }
-
- /**
- * Starts the query against the address book database.
- */
- @Override
- protected void run()
- {
- String filename = super.getContactSource().getFilename();
- File file = new File(filename);
- try
- {
- if (file.lastModified() > getContactSource().lastDatabaseFileChange)
- {
- // parse the Thunderbird Mork database
- InputStreamReader sr =
- new InputStreamReader(new FileInputStream(filename));
- MorkDocument md = new MorkDocument(sr);
- sr.close();
-
- // We now have rows in their tables and additional rows at
- // transaction level. Put the to a better format:
- // DB -> Tables -> Rows
- Map<String, Map<String, Row>> db =
- new HashMap<String, Map<String, Row>>();
- for (Table t : md.getTables())
- {
- String tableId = t.getTableId() + "/" + t.getScopeName();
- Map<String, Row> table = db.get(tableId);
- if (table == null)
- {
- table = new HashMap<String, Row>();
- db.put(tableId, table);
- }
-
- for (Row r : t.getRows())
- {
- String scope = r.getScopeName();
- if (scope == null)
- {
- scope = t.getScopeName();
- }
-
- table.put(r.getRowId() + "/" + scope, r);
- }
- }
-
- // The additional rows at the root-level update/replace the ones
- // in the tables. There's usually neither a table nor a scope
- // defined, so lets just use the default.
- String defaultScope = md.getDicts().get(0).dereference("^80");
- for (Row r : md.getRows())
- {
- String scope = r.getScopeName();
- if (scope == null)
- {
- scope = defaultScope;
- }
-
- String tableId = "1/" + scope;
- Map<String, Row> table = db.get(tableId);
- if (table == null)
- {
- table = new HashMap<String, Row>();
- db.put(tableId, table);
- }
-
- String rowId = r.getRowId() + "/" + scope;
- if (rowId.startsWith("-"))
- {
- rowId = rowId.substring(1);
- }
-
- table.put(rowId, r);
- }
-
- super.getContactSource().database = db;
- super.getContactSource().defaultScope = defaultScope;
- super.getContactSource().lastDatabaseFileChange =
- file.lastModified();
- }
-
- // okay, "transactions" are applied, now perform the search
- for (Entry<String, Map<String, Row>> table
- : super.getContactSource().database.entrySet())
- {
- for (Map.Entry<String, Row> e : table.getValue().entrySet())
- {
- if (e.getKey().endsWith(getContactSource().defaultScope))
- {
- readEntry(e.getValue());
- }
- }
- }
-
- super.stopped(true);
- }
- catch (FileNotFoundException e)
- {
- logger.warn("Could not open address book", e);
- }
- catch (Exception e)
- {
- logger.warn("Could not parse " + file, e);
- }
- }
-
- /**
- * Processes a database row by matching it against the query and adding it
- * to the result set if it matched.
- *
- * @param r The database row representing a contact.
- */
- private void readEntry(Row r)
- {
- // match the pattern against this contact
- boolean hadMatch = false;
- for (Alias value : r.getAliases().values())
- {
- if (value != null
- && (super.query.matcher(value.getValue()).find() || super
- .phoneNumberMatches(value.getValue())))
- {
- hadMatch = true;
- break;
- }
- }
-
- // nope, didn't match, ignore
- if (!hadMatch)
- {
- return;
- }
-
- List<ContactDetail> details = new LinkedList<ContactDetail>();
-
- // e-mail(s)
- for (String email : getPropertySet(r, "PrimaryEmail", "SecondEmail",
- "DefaultEmail"))
- {
- ContactDetail detail = new ContactDetail(email, Category.Email);
- detail.addSupportedOpSet(OperationSetPersistentPresence.class);
- details.add(detail);
- }
-
- // phone number(s)
- this.addPhoneDetail(details, r, "HomePhone", SubCategory.Home);
- this.addPhoneDetail(details, r, "WorkPhone", SubCategory.Work);
- this.addPhoneDetail(details, r, "CellularNumber", SubCategory.Mobile);
-
- // and the dispaly name
- String displayName = r.getValue("DisplayName");
- if (StringUtils.isNullOrEmpty(displayName, true))
- {
- displayName = r.getValue("LastName");
- if (displayName != null)
- {
- displayName = displayName.trim();
- }
-
- String firstName = r.getValue("FirstName");
- if (!StringUtils.isNullOrEmpty(firstName, true))
- {
- displayName = firstName + " " + displayName;
- }
- }
-
- // create the contact and add it to the results
- GenericSourceContact sc =
- new GenericSourceContact(super.getContactSource(), displayName,
- details);
- addQueryResult(sc);
- }
-
- /**
- * Adds a "Phone" {@link ContactDetail} to a query contact.
- *
- * @param details The {@link List} of {@link ContactDetail}s to which the
- * details is added.
- * @param r The source database row of the contact.
- * @param property The source database property name to add as a detail.
- * @param category The Phone-{@link SubCategory} for the phone number to
- * add.
- */
- private void addPhoneDetail(List<ContactDetail> details, Row r,
- String property, SubCategory category)
- {
- String phone = r.getValue(property);
- if (StringUtils.isNullOrEmpty(phone, true))
- {
- return;
- }
-
- phone
- = ThunderbirdActivator.getPhoneNumberI18nService().normalize(phone);
- ContactDetail detail =
- new ContactDetail(phone, ContactDetail.Category.Phone,
- new ContactDetail.SubCategory[]
- { category });
-
- detail.addSupportedOpSet(OperationSetBasicTelephony.class);
- detail.addSupportedOpSet(OperationSetPersistentPresence.class);
- details.add(detail);
- }
-
- /**
- * Gets a set of non-empty properties from the source database row.
- *
- * @param r The source database row to process.
- * @param properties The property-names to extract.
- * @return A set of non-empty properties from the source database row.
- */
- private Set<String> getPropertySet(Row r, String... properties)
- {
- Set<String> validValues = new HashSet<String>(properties.length);
- for (String prop : properties)
- {
- String value = r.getValue(prop);
- if (!StringUtils.isNullOrEmpty(value, true))
- {
- validValues.add(value);
- }
- }
-
- return validValues;
- }
-}
+package net.java.sip.communicator.plugin.thunderbird; + +import java.io.*; +import java.util.*; +import java.util.Map.Entry; +import java.util.regex.*; + +import org.jitsi.util.StringUtils; + +import mork.*; +import net.java.sip.communicator.service.contactsource.*; +import net.java.sip.communicator.service.contactsource.ContactDetail.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; + +/** + * Queries a Thunderbird address book for contacts matching the given pattern. + * + * @author Ingo Bauersachs + */ +public class ThunderbirdContactQuery + extends AsyncContactQuery<ThunderbirdContactSourceService> +{ + /** Class logger */ + private final static Logger logger = Logger + .getLogger(ThunderbirdContactQuery.class); + + /** + * Creates a new instance of this class. + * + * @param owner The contact source that created this query. + * @param query The pattern to match against the contacts database. + */ + public ThunderbirdContactQuery(ThunderbirdContactSourceService owner, + Pattern query) + { + super(owner, query); + } + + /** + * Starts the query against the address book database. + */ + @Override + protected void run() + { + String filename = super.getContactSource().getFilename(); + File file = new File(filename); + try + { + if (file.lastModified() > getContactSource().lastDatabaseFileChange) + { + // parse the Thunderbird Mork database + InputStreamReader sr = + new InputStreamReader(new FileInputStream(filename)); + MorkDocument md = new MorkDocument(sr); + sr.close(); + + // We now have rows in their tables and additional rows at + // transaction level. Put the to a better format: + // DB -> Tables -> Rows + Map<String, Map<String, Row>> db = + new HashMap<String, Map<String, Row>>(); + for (Table t : md.getTables()) + { + String tableId = t.getTableId() + "/" + t.getScopeName(); + Map<String, Row> table = db.get(tableId); + if (table == null) + { + table = new HashMap<String, Row>(); + db.put(tableId, table); + } + + for (Row r : t.getRows()) + { + String scope = r.getScopeName(); + if (scope == null) + { + scope = t.getScopeName(); + } + + table.put(r.getRowId() + "/" + scope, r); + } + } + + // The additional rows at the root-level update/replace the ones + // in the tables. There's usually neither a table nor a scope + // defined, so lets just use the default. + String defaultScope = md.getDicts().get(0).dereference("^80"); + for (Row r : md.getRows()) + { + String scope = r.getScopeName(); + if (scope == null) + { + scope = defaultScope; + } + + String tableId = "1/" + scope; + Map<String, Row> table = db.get(tableId); + if (table == null) + { + table = new HashMap<String, Row>(); + db.put(tableId, table); + } + + String rowId = r.getRowId() + "/" + scope; + if (rowId.startsWith("-")) + { + rowId = rowId.substring(1); + } + + table.put(rowId, r); + } + + super.getContactSource().database = db; + super.getContactSource().defaultScope = defaultScope; + super.getContactSource().lastDatabaseFileChange = + file.lastModified(); + } + + // okay, "transactions" are applied, now perform the search + for (Entry<String, Map<String, Row>> table + : super.getContactSource().database.entrySet()) + { + for (Map.Entry<String, Row> e : table.getValue().entrySet()) + { + if (e.getKey().endsWith(getContactSource().defaultScope)) + { + readEntry(e.getValue()); + } + } + } + + super.stopped(true); + } + catch (FileNotFoundException e) + { + logger.warn("Could not open address book", e); + } + catch (Exception e) + { + logger.warn("Could not parse " + file, e); + } + } + + /** + * Processes a database row by matching it against the query and adding it + * to the result set if it matched. + * + * @param r The database row representing a contact. + */ + private void readEntry(Row r) + { + // match the pattern against this contact + boolean hadMatch = false; + for (Alias value : r.getAliases().values()) + { + if (value != null + && (super.query.matcher(value.getValue()).find() || super + .phoneNumberMatches(value.getValue()))) + { + hadMatch = true; + break; + } + } + + // nope, didn't match, ignore + if (!hadMatch) + { + return; + } + + List<ContactDetail> details = new LinkedList<ContactDetail>(); + + // e-mail(s) + for (String email : getPropertySet(r, "PrimaryEmail", "SecondEmail", + "DefaultEmail")) + { + ContactDetail detail = new ContactDetail(email, Category.Email); + detail.addSupportedOpSet(OperationSetPersistentPresence.class); + details.add(detail); + } + + // phone number(s) + this.addPhoneDetail(details, r, "HomePhone", SubCategory.Home); + this.addPhoneDetail(details, r, "WorkPhone", SubCategory.Work); + this.addPhoneDetail(details, r, "CellularNumber", SubCategory.Mobile); + + // and the dispaly name + String displayName = r.getValue("DisplayName"); + if (StringUtils.isNullOrEmpty(displayName, true)) + { + displayName = r.getValue("LastName"); + if (displayName != null) + { + displayName = displayName.trim(); + } + + String firstName = r.getValue("FirstName"); + if (!StringUtils.isNullOrEmpty(firstName, true)) + { + displayName = firstName + " " + displayName; + } + } + + // create the contact and add it to the results + GenericSourceContact sc = + new GenericSourceContact(super.getContactSource(), displayName, + details); + addQueryResult(sc); + } + + /** + * Adds a "Phone" {@link ContactDetail} to a query contact. + * + * @param details The {@link List} of {@link ContactDetail}s to which the + * details is added. + * @param r The source database row of the contact. + * @param property The source database property name to add as a detail. + * @param category The Phone-{@link SubCategory} for the phone number to + * add. + */ + private void addPhoneDetail(List<ContactDetail> details, Row r, + String property, SubCategory category) + { + String phone = r.getValue(property); + if (StringUtils.isNullOrEmpty(phone, true)) + { + return; + } + + phone + = ThunderbirdActivator.getPhoneNumberI18nService().normalize(phone); + ContactDetail detail = + new ContactDetail(phone, ContactDetail.Category.Phone, + new ContactDetail.SubCategory[] + { category }); + + detail.addSupportedOpSet(OperationSetBasicTelephony.class); + detail.addSupportedOpSet(OperationSetPersistentPresence.class); + details.add(detail); + } + + /** + * Gets a set of non-empty properties from the source database row. + * + * @param r The source database row to process. + * @param properties The property-names to extract. + * @return A set of non-empty properties from the source database row. + */ + private Set<String> getPropertySet(Row r, String... properties) + { + Set<String> validValues = new HashSet<String>(properties.length); + for (String prop : properties) + { + String value = r.getValue(prop); + if (!StringUtils.isNullOrEmpty(value, true)) + { + validValues.add(value); + } + } + + return validValues; + } +} |