/* * FrontlineSMS <http://www.frontlinesms.com> * Copyright 2007, 2008 kiwanja * * This file is part of FrontlineSMS. * * FrontlineSMS is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * * FrontlineSMS is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with FrontlineSMS. If not, see <http://www.gnu.org/licenses/>. */ package net.frontlinesms.messaging.mms; import java.util.Collection; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import net.frontlinesms.AppProperties; import net.frontlinesms.FrontlineUtils; import net.frontlinesms.data.DuplicateKeyException; import net.frontlinesms.data.domain.EmailAccount; import net.frontlinesms.data.domain.FrontlineMultimediaMessage; import net.frontlinesms.data.repository.EmailAccountDao; import net.frontlinesms.events.EventBus; import net.frontlinesms.messaging.mms.email.MmsEmailService; import net.frontlinesms.messaging.mms.email.MmsEmailServiceStatus; import net.frontlinesms.messaging.mms.events.MmsReceivedNotification; import net.frontlinesms.mms.MmsMessage; import net.frontlinesms.mms.MmsReceiveException; import org.apache.log4j.Logger; /** * MmsServiceManager runs as a separate thread. * * It handles the discovery of Multimedia Messages available on the e-mail accounts configures by the user, * * INCOMING MESSAGES * When a new MMS is filtered in the list of e-mails, an event is triggered through the {@link EventBus} * * Incoming messages are immediately removed from accounts with a POP protocol * * @author Morgan Belkadi <morgan@frontlinesms.com> */ public class MmsServiceManager extends Thread { /** Set of {@link MmsEmailService} */ private final Set<MmsService> mmsEmailServices = new CopyOnWriteArraySet<MmsService>(); /** Flag indicating that the thread should continue running. */ private boolean running; private EventBus eventBus; private EmailAccountDao emailAccountDao; private static Logger LOG = FrontlineUtils.getLogger(MmsServiceManager.class); public MmsServiceManager() { super("MmsServiceManager"); // TODO Is there a cleaner way of doing this? Email.receive() blocks in run().processMmsEmailReceiving() this.setDaemon(true); } public void setEventBus(EventBus eventBus) { this.eventBus = eventBus; } /** * Adds a new {@link EmailAccount} which will be used to receive Multimedia Messages * @param emailAccount */ public synchronized void addMmsEmailReceiver(EmailAccount emailAccount) { MmsEmailService mmsEmailService = new MmsEmailService(emailAccount); mmsEmailServices.add(mmsEmailService); } /** * Remove the {@link EmailAccount} from the list * @param emailAccount */ public synchronized void removeMmsEmailReceiver(EmailAccount emailAccount) { for (MmsService mmsEmailService : this.mmsEmailServices) { if (((MmsEmailService)mmsEmailService).getEmailAccount().equals(emailAccount)) { this.mmsEmailServices.remove(mmsEmailService); } } } /** * * @return All {@link MmsService}s */ public Set<MmsService> getAll () { return this.mmsEmailServices; } /** * Starts the thread. * Frequently fetches for new {@link FrontlineMultimediaMessage} */ public void run() { LOG.trace("ENTER"); running = true; while (running) { processMmsEmailReceiving(); FrontlineUtils.sleep_ignoreInterrupts(AppProperties.getInstance().getMmsPollingFrequency()); } LOG.trace("EXIT"); } /** * Flags the internal thread to stop running. */ public void stopRunning() { this.running = false; } /** * Processes the retrieving of e-mails. * Automatically sets the status of the {@link MmsEmailService} depending on its state */ private void processMmsEmailReceiving() { for (MmsService mmsService : this.mmsEmailServices) { if (mmsService.isConnected()) { MmsEmailService mmsEmailService = (MmsEmailService)mmsService; try { mmsEmailService.setStatus(MmsEmailServiceStatus.FETCHING, this.eventBus); Collection<MmsMessage> mmsMessages = mmsEmailService.receive(); for (MmsMessage mmsMessage : mmsMessages) { if (this.eventBus != null) { // Let's notify the observers that a new MMS has arrived this.eventBus.notifyObservers(new MmsReceivedNotification(mmsMessage)); } } mmsEmailService.setStatus(MmsEmailServiceStatus.READY, this.eventBus); /** Last check update */ // First, check if the service has not been removed if (this.mmsEmailServices.contains(mmsEmailService)) { mmsEmailService.updateLastCheck(this.emailAccountDao); } } catch (MmsReceiveException e) { mmsEmailService.setStatus(MmsEmailServiceStatus.FAILED_TO_CONNECT, this.eventBus); } } } } public void clearMmsEmailReceivers() { this.mmsEmailServices.clear(); } public void setEmailAccountDao(EmailAccountDao emailAccountDao) { this.emailAccountDao = emailAccountDao; } /** * Connect the {@link MmsEmailService} * @param mmsEmailService * @param connect */ public void connectMmsEmailService(MmsEmailService mmsEmailService, boolean connect) { mmsEmailService.setStatus((connect ? MmsEmailServiceStatus.READY : MmsEmailServiceStatus.DISCONNECTED), this.eventBus); EmailAccount emailAccount = mmsEmailService.getEmailAccount(); emailAccount.setEnabled(connect); try { this.emailAccountDao.updateEmailAccount(mmsEmailService.getEmailAccount()); } catch (DuplicateKeyException e) { } } /** * Update the {@link MmsEmailService}s */ public synchronized void updateMmsEmailService(EmailAccount emailAccount) { for (MmsService mmsService : this.mmsEmailServices) { MmsEmailService mmsEmailService = (MmsEmailService) mmsService; if (mmsEmailService.getEmailAccount().isSameDatabaseEntity(emailAccount)) { mmsEmailService.populateReceiver(emailAccount); mmsEmailService.setEmailAccount(emailAccount); mmsEmailService.setStatus((emailAccount.isEnabled() ? MmsEmailServiceStatus.READY : MmsEmailServiceStatus.DISCONNECTED), this.eventBus); } } } /** * @return The number of active MMS connections running */ public int getNumberOfActiveConnections() { int total = 0; for(MmsService modem : this.mmsEmailServices) { if (modem.isConnected()) { ++total; } } return total; } }