class Toaster(Item): implements(IBreadConsumer) powerupInterfaces = (IAppliance, IBreadConsumer) powerStrip = dependency.dependsOn(PowerStrip, lambda ps: ps.setForUSElectricity(), doc="the power source for this toaster") description = text() breadFactory = dependency.dependsOn( Breadbox, doc="the thing we get bread input from", whenDeleted=reference.CASCADE) callback = inmemory() def activate(self): self.callback = None def installed(self): if self.callback is not None: self.callback("installed") def uninstalled(self): if self.callback is not None: self.callback("uninstalled") def toast(self): self.powerStrip.draw(100) self.breadFactory.dispenseBread(2)
class GrabberConfiguration(item.Item): """ Manages the creation, operation, and destruction of grabbers (items which retrieve information from remote sources). """ schemaVersion = 3 paused = attributes.boolean(doc=""" Flag indicating whether grabbers created by this Item will be allowed to run. """, default=False) privateApplication = dependsOn(PrivateApplication) deliveryAgent = dependsOn(DeliveryAgent) def addGrabber(self, username, password, domain, ssl): # DO IT if ssl: port = 995 else: port = 110 pg = POP3Grabber(store=self.store, username=username, password=password, domain=domain, port=port, config=self, ssl=ssl) # DO IT *NOW* self.scheduler.schedule(pg, extime.Time())
class MessageSearchProvider(Item): """ Wrapper around an ISearchProvider which will hand back search results wrapped in a fragment that knows about Messages. """ schemaVersion = 2 indexer = dependsOn(fulltext.PyLuceneIndexer, doc=""" The actual fulltext indexing implementation object which will perform searches. The results it returns will be wrapped up in a fragment which knows how to display L{exmess.Message} instances. """) messageSource = dependsOn(mail.MessageSource) powerupInterfaces = (ixmantissa.ISearchProvider, ) def installed(self): self.indexer.addSource(self.messageSource) def count(self, term): raise NotImplementedError("No one should ever call count, I think.") def search(self, *a, **k): if 'sortAscending' not in k: k['sortAscending'] = False d = self.indexer.search(*a, **k) d.addCallback(_mailsearchui.SearchAggregatorFragment, self.store) return d
class ExtractPowerup(Item): schemaVersion = 2 gallery = dependsOn(Gallery) thumbnailDisplayer = dependsOn(ThumbnailDisplayer) def installed(self): self.store.findUnique(mail.MessageSource).addReliableListener(self) def processItem(self, message): extractImages(message) for et in extractTypes.itervalues(): et.extract(message)
class Calendar(Item, AMPReceiver): powerupInterfaces = (IMessageReceiver, INavigableElement) implements(*powerupInterfaces) messageQueue = dependsOn(MessageQueue) # Possibly inappropriate. See #2573. privateApplication = dependsOn(PrivateApplication) def installed(self): getEveryoneRole(self.store).shareItem(self, CALENDAR_SHARE_ID, [IMessageReceiver]) @commandMethod.expose(MakeAppointment) def peerRequestedAppointment(self, whom, when): app = Appointment( store=self.store, when=Time.fromISO8601TimeAndDate(when), withWhomUsername=whom.localpart, withWhomDomain=whom.domain, withWhomShareID=whom.shareID, remoteID=whom.shareID) role = getPrimaryRole(self.store, u"%s@%s" % (whom.localpart, whom.domain), True) appointmentID = role.shareItem(app, interfaces=[IMessageReceiver]).shareID return {'appointmentID': appointmentID} def requestAppointmentWith(self, whom, when): appointment = Appointment( store=self.store, when=when, withWhomShareID=whom.shareID, withWhomUsername=whom.localpart, withWhomDomain=whom.domain) role = getPrimaryRole(self.store, u"%s@%s" % (whom.localpart, whom.domain), True) appointmentID = role.shareItem(appointment, interfaces=[IMessageReceiver]).shareID messenger = AMPMessenger( self.messageQueue, Identifier(appointmentID, *getAccountNames(self.store).next()), whom) messenger.messageRemote( MakeAppointment, appointment, when=when.asISO8601TimeAndDate()) def calendarIDFor(self, local, domain): return Identifier(CALENDAR_SHARE_ID, local, domain) def getAppointments(self): return self.store.query(Appointment) def getTabs(self): return [Tab("Calendar", self.storeID, 1.0)]
class Blender(Item): powerStrip = dependency.dependsOn(PowerStrip, powerstripSetup) description = text() def __getPowerupInterfaces__(self, powerups): yield (IAppliance, 0)
class ConfessionDispatcher(Item): implements(sip.IVoiceSystem) typeName = "sine_confession_dispatcher" schemaVersion = 1 installedOn = reference() localHost = bytes() uas = inmemory() confessionUser = dependsOn(ConfessionUser) powerupInterfaces = (sip.IVoiceSystem, ) def activate(self): svc = self.store.parent.findUnique(sipserver.SIPServer) self.uas = useragent.UserAgent.server(self, self.localHost, svc.mediaController) def lookupProcessor(self, msg, dialogs): #XXX haaaaack if 'confession@' in msg.headers['to'][0]: #double hack =/ self.uas.dialogs = dialogs return self.uas def localElementByName(self, name): if name == 'confession': return self.confessionUser else: raise sip.SIPLookupError(404)
class SIPDispatcherService(Item, Service): typeName = 'sine_sipdispatcher_service' schemaVersion = 3 portno = integer(default=5060) parent = inmemory() running = inmemory() name = inmemory() dispatcher = inmemory() proxy = inmemory() port = inmemory() site = inmemory() userbase = dependsOn(LoginSystem) powerupInterfaces = (IService, ) def privilegedStartService(self): portal = Portal(self.userbase, [self.userbase]) self.proxy = sip.Proxy(portal) self.dispatcher = sip.SIPDispatcher(portal, self.proxy) f = sip.SIPTransport(self.dispatcher, getHostnames(self.store), self.portno) self.port = reactor.listenUDP(self.portno, f)
class MessageLister(Item): implements(ixmantissa.IOrganizerPlugin) typeName = 'quotient_message_lister_plugin' schemaVersion = 2 installedOn = attributes.reference() powerupInterfaces = (ixmantissa.IOrganizerPlugin,) organizer = dependsOn(people.Organizer) name = u'Messages' def personalize(self, person): return MessageList(self, person) def mostRecentMessages(self, person, n=5): """ @param person: L{xmantissa.people.Person} @return: sequence of C{n} L{xquotient.exmess.Message} instances, each one a message either to or from C{person}, ordered descendingly by received date. """ sq = MailboxSelector(self.store) sq.refineByStatus(CLEAN_STATUS) sq.refineByPerson(person) sq.setLimit(n) sq.setNewestFirst() return list(sq)
class AMPConfiguration(Item): """ Configuration object for a Mantissa AMP server. @ivar ONE_TIME_PAD_DURATION: The duration of each one-time pad, in seconds. @type ONE_TIME_PAD_DURATION: C{int} """ powerupInterfaces = (IProtocolFactoryFactory, IOneTimePadGenerator) implements(*powerupInterfaces) schemaVersion = 2 loginSystem = dependsOn(LoginSystem) _oneTimePads = inmemory() ONE_TIME_PAD_DURATION = 60 * 2 callLater = staticmethod(reactor.callLater) def activate(self): """ Initialize L{_oneTimePads} """ self._oneTimePads = {} # IOneTimePadGenerator def generateOneTimePad(self, userStore): """ Generate a pad which can be used to authenticate via AMP. This pad will expire in L{ONE_TIME_PAD_DURATION} seconds. """ pad = secureRandom(16).encode('hex') self._oneTimePads[pad] = userStore.idInParent def expirePad(): self._oneTimePads.pop(pad, None) self.callLater(self.ONE_TIME_PAD_DURATION, expirePad) return pad # IProtocolFactoryFactory def getFactory(self): """ Return a server factory which creates AMP protocol instances. """ factory = ServerFactory() def protocol(): proto = CredReceiver() proto.portal = Portal( self.loginSystem, [self.loginSystem, OneTimePadChecker(self._oneTimePads)]) return proto factory.protocol = protocol return factory
class MailingListFilteringPowerup(item.Item): """ Filters mail according to the mailing list it was sent from. """ schemaVersion = 2 tagCatalog = dependsOn(Catalog, doc=""" The catalog in which to tag items to which this action is applied. """) mailingListRule = dependsOn(MailingListRule, doc=""" The mailing list filter used by this powerup. """) messageSource = dependsOn(mail.MessageSource) def installed(self): self.messageSource.addReliableListener(self) def processItem(self, item): matched, proceed, extraData = self.mailingListRule.applyTo(item) if matched: self.mailingListRule.getAction().actOn(self, self.mailingListRule, item, extraData)
class ContentResource(Item): """ Resource for accessing the content store. """ implements(IResource) powerupInterfaces = [IResource] addSlash = inmemory() contentStore = dependsOn(ContentStore) def getObject(self, name): def _notFound(f): f.trap(NonexistentObject) return None return self.contentStore.getSiblingObject(name).addErrback(_notFound) def childFactory(self, name): """ Hook up children. / is the root, nothing to see her. /new is how new objects are stored. /<objectId> is where existing objects are retrieved. """ if name == '': return self elif name == 'new': return ObjectCreator(self.contentStore) else: return self.getObject(name) return None # IResource def renderHTTP(self, ctx): """ Nothing to see here. """ return 'Entropy' def locateChild(self, ctx, segments): """ Dispatch to L{childFactory}. """ if len(segments) >= 1: res = self.childFactory(segments[0]) if res is not None: return res, segments[1:] return NotFound
class AnonymousSite(item.Item, SiteRootMixin): """ Root IResource implementation for unauthenticated users. This resource allows users to login, reset their passwords, or access content provided by any site root plugins. """ powerupInterfaces = (IResource, IMantissaSite, IWebViewer) implements(*powerupInterfaces + (IPowerupIndirector, )) schemaVersion = 2 loginSystem = dependsOn(userbase.LoginSystem) def rootChild_resetPassword(self, req, webViewer): """ Return a page which will allow the user to re-set their password. """ from xmantissa.signup import PasswordResetResource return PasswordResetResource(self.store) def rootChild_login(self, req, webViewer): """ Return a login page. """ return LoginPage(self.store) def rootChild_users(self, req, webViewer): """ Return a child resource to provide access to items shared by users. @return: a resource whose children will be private pages of individual users. @rtype L{xmantissa.websharing.UserIndexPage} """ return UserIndexPage(self.loginSystem, webViewer) def _getUsername(self): """ Inform L{VirtualHostWrapper} that it's being accessed anonymously. """ return None # IPowerupIndirector def indirect(self, interface): """ Indirect the implementation of L{IWebViewer} to L{_AnonymousWebViewer}. """ if interface == IWebViewer: return _AnonymousWebViewer(self.store) return super(AnonymousSite, self).indirect(interface)
class RuleFilteringPowerup(item.Item): """ Filters messages according to a set of user-defined filtering rules. """ typeName = 'xquotient_filter_filteringpowerup' schemaVersion = 2 tagCatalog = dependsOn(Catalog, doc=""" The catalog in which to tag items to which this action is applied. """) messageSource = dependsOn(mail.MessageSource) filters = attributes.inmemory() powerupInterfaces = (ixmantissa.INavigableElement,) def activate(self): self.filters = None def installed(self): self.messageSource.addReliableListener(self) def getTabs(self): return [webnav.Tab('Mail', self.storeID, 0.2, children= [webnav.Tab('Filtering', self.storeID, 0.1)], authoritative=False)] def processItem(self, item): if self.filters is None: self.filters = list(self.powerupsFor(iquotient.IFilteringRule)) for f in self.filters: matched, proceed, extraData = f.applyTo(item) if matched: f.getAction().actOn(self, f, item, extraData) if not proceed: break
class AdminStatsApplication(Item): """ Obsolete. Only present for schema compatibility. Do not use. """ powerupInterfaces = (INavigableElement,) implements(INavigableElement) schemaVersion = 2 typeName = 'administrator_application' updateInterval = integer(default=5) privateApplication = dependsOn(PrivateApplication) def getTabs(self): return []
class DSPAMFilter(item.Item): """ libdspam-based L{iquotient.IHamFilter} powerup. """ implements(iquotient.IHamFilter) schemaVersion = 2 classifier = attributes.inmemory() username = attributes.inmemory() lib = attributes.inmemory() globalPath = attributes.bytes() filter = dependsOn(Filter) powerupInterfaces = (iquotient.IHamFilter, ) def installed(self): self.globalPath = self.store.parent.newFilePath("dspam").path def _homePath(self): return self.store.newFilePath('dspam-%d' % (self.storeID, )) def activate(self): username, domain = userbase.getAccountNames(self.store).next() self.username = ("%s@%s" % (username, domain)).encode('ascii') self.lib = dspam.startDSPAM(self.username, self._homePath().path.encode('ascii')) def classify(self, item): result, clas, conf = dspam.classifyMessageWithGlobalGroup( self.lib, self.username, 'global', self._homePath().path.encode('ascii'), self.globalPath, item.impl.source.open().read(), train=True) return result == dspam.DSR_ISSPAM, conf def train(self, spam, item): dspam.trainMessageFromError( self.lib, self.username, self._homePath().path.encode('ascii'), item.impl.source.open().read(), spam and dspam.DSR_ISSPAM or dspam.DSR_ISINNOCENT) def forgetTraining(self): p = self._homePath() if p.exists(): p.remove()
class Focus(Item): """ Implement the rules which determine whether a message gets the focused status or not. """ implements(IReliableListener) messageSource = dependsOn(MessageSource) def installed(self): self.messageSource.addReliableListener(self) def processItem(self, item): """ Apply the focus status to any incoming message which is probably not a mailing list message. """ for s in item.iterStatuses(): if s in [DRAFT_STATUS, OUTBOX_STATUS, BOUNCED_STATUS, SENT_STATUS]: return part = item.impl try: getHeader = part.getHeader except AttributeError: pass else: try: precedence = getHeader(u'precedence') except NoSuchHeader: item.focus() else: if precedence.lower() not in (u'list', u'bulk'): item.focus() def suspend(self): """ Called when this listener is suspended. There is no ephemeral state for this listener so this function does nothing. """ def resume(self): """
class SpambayesFilter(item.Item): """ Spambayes-based L{iquotient.IHamFilter} powerup. """ implements(iquotient.IHamFilter) schemaVersion = 3 classifier = attributes.inmemory() guesser = attributes.inmemory() filter = dependsOn(Filter) powerupInterfaces = (iquotient.IHamFilter, ) def _classifierPath(self): return self.store.newFilePath('spambayes-%d-classifier.sqlite' % (self.storeID, )) def activate(self): self.classifier = _SQLite3Classifier(self._classifierPath().path) self.guesser = hammie.Hammie(self.classifier, mode='r') # IHamFilter def classify(self, item): # SpamBayes thinks 0 is ham, 1 is spam. We have a different idea. score = 1.0 - self.guesser.score(item.impl.source.open()) return score <= SPAM_THRESHHOLD, score def train(self, spam, item): """ Train the classifier. @param spam: A boolean indicating whether C{item} is spam or not. @param item: A Message to train with. """ for i in xrange(10): self.guesser.train(item.impl.source.open(), spam) if spam: if self.classify(item) < SPAM_THRESHHOLD: break else: if self.classify(item) > SPAM_THRESHHOLD: break def forgetTraining(self): p = self._classifierPath() if p.exists(): p.remove() self.activate()
class ImaginaryApp(Item): """ A terminal application which presents an Imaginary game session. """ powerupInterfaces = (ITerminalServerFactory, ) implements(*powerupInterfaces) shell = dependsOn(ShellAccount) name = 'imaginary' def _charactersForViewer(self, store, role): """ Find the characters the given role is allowed to play. This will load any L{Thing}s from C{store} which are shared to C{role}. It then unwraps them from their sharing wrapper and returns them (XXX there should really be a way for this to work without the unwrapping, no? See #2909. -exarkun). """ characters = [] things = store.query(Thing) actors = asAccessibleTo(role, things) characters.extend(map(itemFromProxy, actors)) return characters def buildTerminalProtocol(self, viewer): """ Create and return a L{TextServer} using a L{Player} owned by the store this item is in. This implementation is certainly wrong. It probably reflects some current limitations of Mantissa. Primarily, the limitation is interaction between different stores, in this case a user store and an application store. """ # XXX Get the Imaginary app store. Eventually this should just be # self.store. See #2908. imaginary = IRealm(self.store.parent).accountByAddress( u'Imaginary', None).avatars.open() role = viewer.roleIn(imaginary) characters = self._charactersForViewer(imaginary, role) world = imaginary.findUnique(ImaginaryWorld) return CharacterSelectionTextServer(role, world, characters)
class TerminalManhole(Item): """ A terminal application which presents an interactive Python session running in the primary Mantissa server process. """ powerupInterfaces = (ITerminalServerFactory, ) implements(*powerupInterfaces) shell = dependsOn(ShellAccount) name = 'manhole' def buildTerminalProtocol(self, shellViewer): """ Create and return a L{ColoredManhole} which includes this item's store in its namespace. """ return ColoredManhole({'db': self.store, 'viewer': shellViewer})
class SecureShellConfiguration(Item): """ Configuration object for a Mantissa SSH server. """ powerupInterfaces = (IProtocolFactoryFactory, ) implements(*powerupInterfaces) loginSystem = dependsOn(LoginSystem) hostKey = bytes(doc=""" An OpenSSH-format string giving the host key for this server. """, allowNone=False, defaultFactory=_generate) def __repr__(self): """ Return a summarized representation of this item. """ fmt = "SecureShellConfiguration(storeID=%d, hostKeyFingerprint='%s')" privateKey = Key.fromString(data=self.hostKey) publicKeyBlob = privateKey.blob() fingerprint = md5(publicKeyBlob).hexdigest() return fmt % (self.storeID, fingerprint) def getFactory(self): """ Create an L{SSHFactory} which allows access to Mantissa accounts. """ privateKey = Key.fromString(data=self.hostKey) public = privateKey.public() factory = SSHFactory() factory.publicKeys = {'ssh-rsa': public} factory.privateKeys = {'ssh-rsa': privateKey} factory.portal = Portal(IRealm(self.store), [ICredentialsChecker(self.store)]) return factory def rotate(self): """ Generate a new host key pair. """ self.hostKey = _generate()
class TracebackViewer(Item): implements(INavigableElement) typeName = 'mantissa_tb_viewer' schemaVersion = 2 allowDeletion = boolean(default=False) privateApplication = dependsOn(PrivateApplication) powerupInterfaces = (INavigableElement,) def getTabs(self): return [webnav.Tab('Admin', self.storeID, 0.0, [webnav.Tab('Errors', self.storeID, 0.3)], authoritative=False)] def _getCollector(self): def ifCreate(coll): installOn(coll, self.store.parent) return self.store.parent.findOrCreate(TracebackCollector, ifCreate)
class DeveloperApplication(Item): """ """ implements(INavigableElement) schemaVersion = 2 typeName = 'developer_application' privateApplication = dependsOn(PrivateApplication) statementCount = integer(default=0) powerupInterfaces = (INavigableElement,) def deletedFromStore(self, *a, **kw): return super(DeveloperApplication, self).deletedFromStore(*a, **kw) # INavigableElement def getTabs(self): return [webnav.Tab('Admin', self.storeID, 0.0, [webnav.Tab('REPL', self.storeID, 0.0)], authoritative=False)]
class LocalUserBrowser(Item): """ XXX I am an unfortunate necessity. This class shouldn't exist, and in fact, will be destroyed at the first possible moment. It's stateless, existing only to serve as a web lookup hook for the UserInteractionFragment view class. """ implements(INavigableElement) typeName = 'local_user_browser' schemaVersion = 2 privateApplication = dependsOn(PrivateApplication) powerupInterfaces = (INavigableElement,) def getTabs(self): return [webnav.Tab('Admin', self.storeID, 0.0, [webnav.Tab('Local Users', self.storeID, 0.1)], authoritative=False)]
class POP3Listener(item.Item): implements(IProtocolFactoryFactory) powerupInterfaces = (IProtocolFactoryFactory, ) typeName = "quotient_pop3listener" schemaVersion = 3 # A cred portal, a Twisted TCP factory and as many as two # IListeningPorts portal = attributes.inmemory() factory = attributes.inmemory() certificateFile = attributes.bytes( "The name of a file on disk containing a private key and certificate " "for use by the POP3 server when negotiating TLS.", default=None) userbase = dependsOn(LoginSystem) # When enabled, toss all traffic into logfiles. debug = False def activate(self): self.portal = None self.factory = None # IProtocolFactoryFactory def getFactory(self): if self.factory is None: self.portal = portal.Portal(self.userbase, [self.userbase]) self.factory = POP3ServerFactory(self.portal) if self.debug: self.factory = policies.TrafficLoggingFactory( self.factory, 'pop3') return self.factory def setServiceParent(self, parent): """
class VoicemailDispatcher(item.Item): implements(sip.IVoiceSystem) typeName = "sine_voicemail_dispatcher" schemaVersion = 2 localHost = bytes() uas = inmemory() powerupInterfaces = (sip.IVoiceSystem,) voicemailUser = dependsOn(AnonConfessionUser) def activate(self): if self.store.parent: svc = self.store.parent.findUnique(sipserver.SIPServer) if svc: self.uas = useragent.UserAgent.server(self, svc.transport.host, svc.mediaController) self.uas.transport = svc.transport def lookupProcessor(self, msg, dialogs): if isinstance(msg, sip.Request) and msg.method == "REGISTER": #not our dept return defer.succeed(None) for name, domain in userbase.getAccountNames(self.store, protocol=u'sip'): if name == sip.parseAddress(msg.headers["to"][0])[1].username: contact = sip.IContact(self.store) def regged(_): return defer.succeed(None) def unregged(e): self.uas.dialogs = dialogs return self.uas return defer.maybeDeferred(contact.getRegistrationInfo, sip.parseAddress(msg.headers["from"][0])[1]).addCallbacks(regged, unregged) else: return defer.succeed(None) def localElementByName(self, n): for name, domain in userbase.getAccountNames(self.store, protocol=u'sip'): #if we got here, we have a SIP account... return useragent.ICallControllerFactory(self.store)
class _SubSchedulerParentHook(Item): schemaVersion = 3 typeName = 'axiom_subscheduler_parent_hook' loginAccount = reference() scheduler = dependsOn(Scheduler) def run(self): """ Tick our C{loginAccount}'s L{SubScheduler}. """ IScheduler(self.loginAccount).tick() def _schedule(self, when): """ Ensure that this hook is scheduled to run at or before C{when}. """ for scheduledAt in self.scheduler.scheduledTimes(self): if when < scheduledAt: self.scheduler.reschedule(self, scheduledAt, when) break else: self.scheduler.schedule(self, when)
class IceCrusher(Item): blender = dependency.dependsOn(Blender)
class SIPServer(Item, Service): typeName = 'mantissa_sip_powerup' schemaVersion = 3 portno = integer(default=5060) pstn = bytes() parent = inmemory() running = inmemory() name = inmemory() proxy = inmemory() dispatcher = inmemory() mediaController = inmemory() port = inmemory() site = inmemory() transport = inmemory() userbase = dependsOn(LoginSystem) powerupInterfaces = (IService, ) def installed(self): self.setServiceParent(self.store) def startService(self): tacPath = sibpath(sine.__file__, "media.tac") self.mediaController = batch.ProcessController( "rtp-transceiver", useragent.LocalControlProtocol(False), tacPath=tacPath) if self.pstn: pstnurl = sip.parseURL(self.pstn) portal = PSTNPortalWrapper(Portal(self.userbase, [self.userbase]), pstnurl.host, pstnurl.port) else: portal = Portal(self.userbase, [self.userbase]) self.proxy = sip.Proxy(portal) self.dispatcher = sip.SIPDispatcher(portal, self.proxy) regs = list(self.store.query(Registration, Registration.parent == self)) if regs: rc = sip.RegistrationClient() self.proxy.installRegistrationClient(rc) for reg in regs: if not (reg.username and reg.domain): raise SIPConfigurationError( "Bad registration URL:", "You need both a username and a domain to register") rc.register(reg.username, reg.password, reg.domain) self.proxy.addProxyAuthentication(reg.username, reg.domain, reg.password) self.transport = sip.SIPTransport(self.dispatcher, getHostnames(self.store), self.portno) self.port = reactor.listenUDP(self.portno, self.transport) def setupCallBetween(self, partyA, partyB): """ Set up a call between party A and party B, and control the signalling for the call. Either URL may refer to any SIP address, there is no requirement that either participant be registered with this proxy. @param partyA: a SIP address (a three-tuple of (name, URL, parameters)) that represents the party initiating the call, i.e. the SIP address of the user who is logged in to the web UI and pushing the button to place the call. (Specifically, this is the user who will be called first and will have to wait for the other user to pick up the call.) @param partyB: a SIP address that represents the party receiving the call. @return: None """ # XXX TODO should probably return a deferred which # fires... something... that would let us take advantage of # the intermediary call signalling, such as ending the call # early... localpart = "clicktocall" host = getHostnames(self.store)[0] controller = tpcc.ThirdPartyCallController(self.dispatcher, localpart, host, self.mediaController, partyA[0], partyB[1]) uac = useragent.UserAgent.client(controller, localpart, host, self.mediaController, self.dispatcher.dialogs) uac.transport = self.dispatcher.transport self.dispatcher.installTemporaryProcessor(sip.URL(host, localpart), uac) uac._doCall(partyA[1], fromName="Divmod")
class SiteConfiguration(Item): """ Configuration object for a Mantissa HTTP server. """ powerupInterfaces = (ISiteURLGenerator, IProtocolFactoryFactory) implements(*powerupInterfaces) loginSystem = dependsOn(LoginSystem) # I don't really want this to have a default value at all, but an Item # which can't be instantiated with only a store parameter can't be used as # a siteRequirement in an Offering. See #538 about offering configuration. # -exarkun hostname = text( doc=""" The primary hostname by which this website will be accessible. This will be superceded by a one-to-many relationship in the future, allowing a host to have multiple recognized hostnames. See #2501. """, allowNone=False, default=u"localhost") httpLog = path(default=None) def _root(self, scheme, hostname, portObj, standardPort): # TODO - real unicode support (but punycode is so bad) if portObj is None: return None portNumber = portObj.portNumber port = portObj.listeningPort if hostname is None: hostname = self.hostname else: hostname = hostname.split(':')[0].encode('ascii') if portNumber == 0: if port is None: return None else: portNumber = port.getHost().port # At some future point, we may want to make pathsegs persistently # configurable - perhaps scheme and hostname as well - in order to # easily support reverse proxying configurations, particularly where # Mantissa is being "mounted" somewhere other than /. See also rootURL # which has some overlap with this method (the difference being # universal vs absolute URLs - rootURL may want to call cleartextRoot # or encryptedRoot in the future). See #417 and #2309. pathsegs = [''] if portNumber != standardPort: hostname = '%s:%d' % (hostname, portNumber) return URL(scheme, hostname, pathsegs) def _getPort(self, portType): return self.store.findFirst( portType, portType.factory == self, default=None) def cleartextRoot(self, hostname=None): """ Return a string representing the HTTP URL which is at the root of this site. @param hostname: An optional unicode string which, if specified, will be used as the hostname in the resulting URL, regardless of the C{hostname} attribute of this item. """ return self._root('http', hostname, self._getPort(TCPPort), 80) def encryptedRoot(self, hostname=None): """ Return a string representing the HTTPS URL which is at the root of this site. @param hostname: An optional unicode string which, if specified, will be used as the hostname in the resulting URL, regardless of the C{hostname} attribute of this item. """ return self._root('https', hostname, self._getPort(SSLPort), 443) def rootURL(self, request): """ Return the URL for the root of this website which is appropriate to use in links generated in response to the given request. @type request: L{twisted.web.http.Request} @param request: The request which is being responded to. @rtype: L{URL} @return: The location at which the root of the resource hierarchy for this website is available. """ host = request.getHeader('host') or self.hostname if ':' in host: host = host.split(':', 1)[0] if (host == self.hostname or host.startswith('www.') and host[len('www.'):] == self.hostname): return URL(scheme='', netloc='', pathsegs=['']) else: if request.isSecure(): return self.encryptedRoot(self.hostname) else: return self.cleartextRoot(self.hostname) def getFactory(self): """ Create an L{AxiomSite} which supports authenticated and anonymous access. """ checkers = [self.loginSystem, AllowAnonymousAccess()] guardedRoot = PersistentSessionWrapper( self.store, Portal(self.loginSystem, checkers), domains=[self.hostname]) unguardedRoot = UnguardedWrapper(self.store, guardedRoot) securingRoot = SecuringWrapper(self, unguardedRoot) logPath = None if self.httpLog is not None: logPath = self.httpLog.path return AxiomSite(self.store, securingRoot, logPath=logPath)