logger = new PostmanLogger ( get_class ( $this ) ); $this->options = PostmanOptions::getInstance (); $this->rootPluginFilenameAndPath = $rootPluginFilenameAndPath; } /** * Initialize the Module * * Perform validation and create configuration error messages. * The module is not in a configured-and-ready state until initialization */ public function init() { // create the scribe $hostname = $this->getHostname (); $this->scribe = $this->createScribe ( $hostname ); // validate the transport and generate error messages $this->configurationMessages = $this->validateTransportConfiguration (); } /** * SendGrid API doesn't care what the hostname or guessed SMTP Server is; it runs it's port test no matter what */ public function getSocketsForSetupWizardToProbe($hostname, $smtpServerGuess) { $hosts = array ( self::createSocketDefinition ( $this->getHostname (), $this->getPort () ) ); return $hosts; } /** * Creates a single socket for the Wizard to test */ protected function createSocketDefinition($hostname, $port) { $socket = array (); $socket ['host'] = $hostname; $socket ['port'] = $port; $socket ['id'] = sprintf ( '%s-%s', $this->getSlug (), $port ); $socket ['transport_id'] = $this->getSlug (); $socket ['transport_name'] = $this->getName (); $socket ['smtp'] = false; return $socket; } /** * * @param unknown $data */ public function prepareOptionsForExport($data) { // no-op return $data; } /** */ public function printActionMenuItem() { printf ( '
  • %s
  • ', $this->getScribe ()->getRequestPermissionLinkText () ); } /** * * @param unknown $queryHostname */ protected function createScribe($hostname) { $scribe = new PostmanNonOAuthScribe ( $hostname ); return $scribe; } /** */ public function enqueueScript() { // no-op, this for subclasses } /** * This method is for internal use */ protected function validateTransportConfiguration() { $this->configuredAndReady = true; $messages = array (); return $messages; } /** */ protected function setNotConfiguredAndReady() { $this->configuredAndReady = false; } /** * A short-hand way of showing the complete delivery method * * @param PostmanModuleTransport $transport * @return string */ public function getPublicTransportUri() { $name = $this->getSlug (); $host = $this->getHostname (); $port = $this->getPort (); $protocol = $this->getProtocol (); return sprintf ( '%s://%s:%s', $protocol, $host, $port ); } /** * The Message From Address */ public function getFromEmailAddress() { return PostmanOptions::getInstance ()->getMessageSenderEmail (); } /** * The Message From Name */ public function getFromName() { return PostmanOptions::getInstance ()->getMessageSenderName (); } public function getEnvelopeFromEmailAddress() { return PostmanOptions::getInstance ()->getEnvelopeSender (); } public function isEmailValidationSupported() { return ! PostmanOptions::getInstance ()->isEmailValidationDisabled (); } /** * Make sure the Senders are configured * * @param PostmanOptions $options * @return boolean */ protected function isSenderConfigured() { $options = PostmanOptions::getInstance (); $messageFrom = $options->getMessageSenderEmail (); return ! empty ( $messageFrom ); } /** * Get the configuration error messages */ public function getConfigurationMessages() { return $this->configurationMessages; } /** * (non-PHPdoc) * * @see PostmanModuleTransport::isConfiguredAndReady() */ public function isConfiguredAndReady() { return $this->configuredAndReady; } /** * (non-PHPdoc) * * @see PostmanModuleTransport::isReadyToSendMail() */ public function isReadyToSendMail() { return $this->isConfiguredAndReady (); } /** * Determines whether Mail Engine locking is needed * * @see PostmanModuleTransport::requiresLocking() */ public function isLockingRequired() { return false; } public function isOAuthUsed($authType) { return $authType == PostmanOptions::AUTHENTICATION_TYPE_OAUTH2; } /** * (non-PHPdoc) * * @see PostmanModuleTransport::isWizardSupported() */ public function isWizardSupported() { return false; } /** * This is for step 2 of the Wizard */ public function printWizardMailServerHostnameStep() { } /** * This is for step 4 of the Wizard */ public function printWizardAuthenticationStep() { } /** * * @return PostmanNonOAuthScribe */ public function getScribe() { return $this->scribe; } /** * * @param unknown $hostname * @param unknown $response */ public function populateConfiguration($hostname) { $configuration = array (); return $configuration; } /** * * @param unknown $winningRecommendation * @param unknown $response */ public function populateConfigurationFromRecommendation($winningRecommendation) { $configuration = array (); $configuration ['message'] = $winningRecommendation ['message']; $configuration [PostmanOptions::TRANSPORT_TYPE] = $winningRecommendation ['transport']; return $configuration; } /** */ public function createOverrideMenu(PostmanWizardSocket $socket, $winningRecommendation, $userSocketOverride, $userAuthOverride) { $overrideItem = array (); $overrideItem ['secure'] = $socket->secure; $overrideItem ['mitm'] = $socket->mitm; $overrideItem ['hostname_domain_only'] = $socket->hostnameDomainOnly; $overrideItem ['reported_hostname_domain_only'] = $socket->reportedHostnameDomainOnly; $overrideItem ['value'] = $socket->id; $overrideItem ['description'] = $socket->label; $overrideItem ['selected'] = ($winningRecommendation ['id'] == $overrideItem ['value']); return $overrideItem; } /* * ****************************************************************** * Not deprecated, but I wish they didn't live here on the superclass */ public function isServiceProviderGoogle($hostname) { return PostmanUtils::endsWith ( $hostname, 'gmail.com' ) || PostmanUtils::endsWith ( $hostname, 'googleapis.com' ); } public function isServiceProviderMicrosoft($hostname) { return PostmanUtils::endsWith ( $hostname, 'live.com' ); } public function isServiceProviderYahoo($hostname) { return strpos ( $hostname, 'yahoo' ); } /* * ******************************** * Unused, deprecated methods follow * ********************************* */ /** * * @deprecated (non-PHPdoc) * @see PostmanTransport::createZendMailTransport() */ public function createZendMailTransport($hostname, $config) { } /** * * @deprecated (non-PHPdoc) * @see PostmanTransport::isTranscriptSupported() */ public function isTranscriptSupported() { return false; } /** * Only here because I can't remove it from the Interface */ public final function getMisconfigurationMessage(PostmanConfigTextHelper $scribe, PostmanOptionsInterface $options, PostmanOAuthToken $token) { } public final function isReady(PostmanOptionsInterface $options, PostmanOAuthToken $token) { return ! ($this->isConfiguredAndReady ()); } public final function isConfigured(PostmanOptionsInterface $options, PostmanOAuthToken $token) { return ! ($this->isConfiguredAndReady ()); } /** * * @deprecated (non-PHPdoc) * @see PostmanTransport::getConfigurationRecommendation() */ public final function getConfigurationRecommendation($hostData) { } /** * * @deprecated (non-PHPdoc) * @see PostmanTransport::getHostsToTest() */ public final function getHostsToTest($hostname) { } protected final function isHostConfigured(PostmanOptions $options) { $hostname = $options->getHostname (); $port = $options->getPort (); return ! (empty ( $hostname ) || empty ( $port )); } /** * * @deprecated (non-PHPdoc) * @see PostmanTransport::createPostmanMailAuthenticator() */ public final function createPostmanMailAuthenticator(PostmanOptions $options, PostmanOAuthToken $authToken) { } } /** * For the transports which depend on Zend_Mail * * @author jasonhendriks * */ abstract class PostmanAbstractZendModuleTransport extends PostmanAbstractModuleTransport implements PostmanZendModuleTransport { private $oauthToken; private $readyForOAuthGrant; /** */ public function __construct($rootPluginFilenameAndPath) { parent::__construct ( $rootPluginFilenameAndPath ); $this->oauthToken = PostmanOAuthToken::getInstance (); } public function getOAuthToken() { return $this->oauthToken; } public function getProtocol() { if ($this->getSecurityType () == PostmanOptions::SECURITY_TYPE_SMTPS) return 'smtps'; else return 'smtp'; } public function getSecurityType() { return PostmanOptions::getInstance ()->getEncryptionType (); } /** * * @param unknown $data */ public function prepareOptionsForExport($data) { $data = parent::prepareOptionsForExport ( $data ); $data [PostmanOptions::BASIC_AUTH_PASSWORD] = PostmanOptions::getInstance ()->getPassword (); return $data; } /** * * @return boolean */ public function isEnvelopeFromValidationSupported() { return $this->isEmailValidationSupported (); } /** */ protected function setReadyForOAuthGrant() { $this->readyForOAuthGrant = true; } /** */ public function printActionMenuItem() { if ($this->readyForOAuthGrant && $this->getAuthenticationType () == PostmanOptions::AUTHENTICATION_TYPE_OAUTH2) { printf ( '
  • %s
  • ', PostmanUtils::getGrantOAuthPermissionUrl (), $this->getScribe ()->getRequestPermissionLinkText () ); } else { parent::printActionMenuItem (); } } /** * * @param unknown $queryHostname */ protected function createScribe($hostname) { $scribe = null; if ($this->isServiceProviderGoogle ( $hostname )) { $scribe = new PostmanGoogleOAuthScribe (); } else if ($this->isServiceProviderMicrosoft ( $hostname )) { $scribe = new PostmanMicrosoftOAuthScribe (); } else if ($this->isServiceProviderYahoo ( $hostname )) { $scribe = new PostmanYahooOAuthScribe (); } else { $scribe = new PostmanNonOAuthScribe ( $hostname ); } return $scribe; } /** * A short-hand way of showing the complete delivery method * * @param PostmanModuleTransport $transport * @return string */ public function getPublicTransportUri() { $transportName = $this->getSlug (); $options = PostmanOptions::getInstance (); $auth = $this->getAuthenticationType ( $options ); $protocol = $this->getProtocol (); $security = $this->getSecurityType (); $host = $this->getHostname ( $options ); $port = $this->getPort ( $options ); if (! empty ( $security ) && $security != 'ssl') { return sprintf ( '%s:%s:%s://%s:%s', $protocol, $security, $auth, $host, $port ); } else { return sprintf ( '%s:%s://%s:%s', $protocol, $auth, $host, $port ); } } /** * (non-PHPdoc) * * @see PostmanModuleTransport::getDeliveryDetails() */ public function getDeliveryDetails() { $this->options = $this->options; $deliveryDetails ['transport_name'] = $this->getTransportDescription ( $this->getSecurityType () ); $deliveryDetails ['host'] = $this->getHostname () . ':' . $this->getPort (); $deliveryDetails ['auth_desc'] = $this->getAuthenticationDescription ( $this->getAuthenticationType () ); /* translators: where (1) is the transport type, (2) is the host, and (3) is the Authentication Type (e.g. Postman will send mail via smtp.gmail.com:465 using OAuth 2.0 authentication.) */ return sprintf ( __ ( 'Postman will send mail via %1$s to %2$s using %3$s authentication.', 'post-smtp' ), '' . $deliveryDetails ['transport_name'] . '', '' . $deliveryDetails ['host'] . '', '' . $deliveryDetails ['auth_desc'] . '' ); } /** * * @param unknown $encType * @return string */ protected function getTransportDescription($encType) { $deliveryDetails = '🔓SMTP'; if ($encType == PostmanOptions::SECURITY_TYPE_SMTPS) { /* translators: where %1$s is the Transport type (e.g. SMTP or SMTPS) and %2$s is the encryption type (e.g. SSL or TLS) */ $deliveryDetails = '🔐SMTPS'; } else if ($encType == PostmanOptions::SECURITY_TYPE_STARTTLS) { /* translators: where %1$s is the Transport type (e.g. SMTP or SMTPS) and %2$s is the encryption type (e.g. SSL or TLS) */ $deliveryDetails = '🔐SMTP-STARTTLS'; } return $deliveryDetails; } /** * * @param unknown $authType */ protected function getAuthenticationDescription($authType) { if (PostmanOptions::AUTHENTICATION_TYPE_OAUTH2 == $authType) { return 'OAuth 2.0'; } else if (PostmanOptions::AUTHENTICATION_TYPE_NONE == $authType) { return _x ( 'no', 'as in "There is no Spoon"', 'post-smtp' ); } else { switch ($authType) { case PostmanOptions::AUTHENTICATION_TYPE_CRAMMD5 : $authDescription = 'CRAM-MD5'; break; case PostmanOptions::AUTHENTICATION_TYPE_LOGIN : $authDescription = 'Login'; break; case PostmanOptions::AUTHENTICATION_TYPE_PLAIN : $authDescription = 'Plain'; break; default : $authDescription = $authType; break; } return sprintf ( '%s (%s)', __ ( 'Password', 'post-smtp' ), $authDescription ); } } /** * Make sure the Senders are configured * * @param PostmanOptions $options * @return boolean */ protected function isEnvelopeFromConfigured() { $options = PostmanOptions::getInstance (); $envelopeFrom = $options->getEnvelopeSender (); return ! empty ( $envelopeFrom ); } /** * (non-PHPdoc) * * @see PostmanTransport::getMisconfigurationMessage() */ protected function validateTransportConfiguration() { parent::validateTransportConfiguration (); $messages = parent::validateTransportConfiguration (); if (! $this->isSenderConfigured ()) { array_push ( $messages, __ ( 'Message From Address can not be empty', 'post-smtp' ) . '.' ); $this->setNotConfiguredAndReady (); } if ($this->getAuthenticationType () == PostmanOptions::AUTHENTICATION_TYPE_OAUTH2) { if (! $this->isOAuth2ClientIdAndClientSecretConfigured ()) { /* translators: %1$s is the Client ID label, and %2$s is the Client Secret label (e.g. Warning: OAuth 2.0 authentication requires an OAuth 2.0-capable Outgoing Mail Server, Sender Email Address, Client ID, and Client Secret.) */ array_push ( $messages, sprintf ( __ ( 'OAuth 2.0 authentication requires a %1$s and %2$s.', 'post-smtp' ), $this->getScribe ()->getClientIdLabel (), $this->getScribe ()->getClientSecretLabel () ) ); $this->setNotConfiguredAndReady (); } } return $messages; } /** * * @return boolean */ protected function isOAuth2ClientIdAndClientSecretConfigured() { $options = PostmanOptions::getInstance (); $clientId = $options->getClientId (); $clientSecret = $options->getClientSecret (); return ! (empty ( $clientId ) || empty ( $clientSecret )); } /** * * @return boolean */ protected function isPasswordAuthenticationConfigured(PostmanOptions $options) { $username = $options->getUsername (); $password = $options->getPassword (); return $this->options->isAuthTypePassword () && ! (empty ( $username ) || empty ( $password )); } /** * * @return boolean */ protected function isPermissionNeeded() { $accessToken = $this->getOAuthToken ()->getAccessToken (); $refreshToken = $this->getOAuthToken ()->getRefreshToken (); return $this->isOAuthUsed ( PostmanOptions::getInstance ()->getAuthenticationType () ) && (empty ( $accessToken ) || empty ( $refreshToken )); } /** * * @param unknown $hostname * @param unknown $response */ public function populateConfiguration($hostname) { $response = parent::populateConfiguration ( $hostname ); $this->logger->debug ( sprintf ( 'populateConfigurationFromRecommendation for hostname %s', $hostname ) ); $scribe = $this->createScribe ( $hostname ); // checks to see if the host is an IP address and sticks the result in the response // IP addresses are not allowed in the Redirect URL $urlParts = parse_url ( $scribe->getCallbackUrl () ); $response ['dot_notation_url'] = false; if (isset ( $urlParts ['host'] )) { if (PostmanUtils::isHostAddressNotADomainName ( $urlParts ['host'] )) { $response ['dot_notation_url'] = true; } } $response ['redirect_url'] = $scribe->getCallbackUrl (); $response ['callback_domain'] = $scribe->getCallbackDomain (); $response ['help_text'] = $scribe->getOAuthHelp (); $response ['client_id_label'] = $scribe->getClientIdLabel (); $response ['client_secret_label'] = $scribe->getClientSecretLabel (); $response ['redirect_url_label'] = $scribe->getCallbackUrlLabel (); $response ['callback_domain_label'] = $scribe->getCallbackDomainLabel (); return $response; } /** * Populate the Ajax response for the Setup Wizard / Manual Configuration * * @param unknown $hostname * @param unknown $response */ public function populateConfigurationFromRecommendation($winningRecommendation) { $response = parent::populateConfigurationFromRecommendation ( $winningRecommendation ); $response [PostmanOptions::AUTHENTICATION_TYPE] = $winningRecommendation ['auth']; if (isset ( $winningRecommendation ['enc'] )) { $response [PostmanOptions::SECURITY_TYPE] = $winningRecommendation ['enc']; } if (isset ( $winningRecommendation ['port'] )) { $response [PostmanOptions::PORT] = $winningRecommendation ['port']; } if (isset ( $winningRecommendation ['hostname'] )) { $response [PostmanOptions::HOSTNAME] = $winningRecommendation ['hostname']; } if (isset ( $winningRecommendation ['display_auth'] )) { $response ['display_auth'] = $winningRecommendation ['display_auth']; } return $response; } /** */ public function createOverrideMenu(PostmanWizardSocket $socket, $winningRecommendation, $userSocketOverride, $userAuthOverride) { $overrideItem = parent::createOverrideMenu ( $socket, $winningRecommendation, $userSocketOverride, $userAuthOverride ); $selected = $overrideItem ['selected']; // only smtp can have multiple auth options $overrideAuthItems = array (); $passwordMode = false; $oauth2Mode = false; $noAuthMode = false; if (isset ( $userAuthOverride ) || isset ( $userSocketOverride )) { if ($userAuthOverride == 'password') { $passwordMode = true; } elseif ($userAuthOverride == 'oauth2') { $oauth2Mode = true; } else { $noAuthMode = true; } } else { if ($winningRecommendation ['display_auth'] == 'password') { $passwordMode = true; } elseif ($winningRecommendation ['display_auth'] == 'oauth2') { $oauth2Mode = true; } else { $noAuthMode = true; } } if ($selected) { if ($socket->auth_crammd5 || $socket->auth_login || $socket->authPlain) { array_push ( $overrideAuthItems, array ( 'selected' => $passwordMode, 'name' => __ ( 'Password (requires username and password)', 'post-smtp' ), 'value' => 'password' ) ); } if ($socket->auth_xoauth || $winningRecommendation ['auth'] == 'oauth2') { array_push ( $overrideAuthItems, array ( 'selected' => $oauth2Mode, 'name' => __ ( 'OAuth 2.0 (requires Client ID and Client Secret)', 'post-smtp' ), 'value' => 'oauth2' ) ); } if ($socket->auth_none) { array_push ( $overrideAuthItems, array ( 'selected' => $noAuthMode, 'name' => __ ( 'None', 'post-smtp' ), 'value' => 'none' ) ); } // marks at least one item as selected if none are selected $atLeastOneSelected = false; $firstItem = null; // don't use variable reference see http://stackoverflow.com/questions/15024616/php-foreach-change-original-array-values foreach ( $overrideAuthItems as $key => $field ) { if (! $firstItem) { $firstItem = $key; } if ($field ['selected']) { $atLeastOneSelected = true; } } if (! $atLeastOneSelected) { $this->logger->debug ( 'nothing selected - forcing a selection on the *first* overrided auth item' ); $overrideAuthItems [$firstItem] ['selected'] = true; } // push the authentication options into the $overrideItem structure $overrideItem ['auth_items'] = $overrideAuthItems; } return $overrideItem; } }