+ $resource = null;
+ }
+
+ $node = explode("@", $parts[0]);
+ if ((count($node) > 2) || (count($node) == 0)) {
+ throw new Exception("Invalid JID: too many @s");
+ } else if (count($node) == 1) {
+ $domain = $node[0];
+ $node = null;
+ } else {
+ $domain = $node[1];
+ $node = $node[0];
+ if ($node == '') {
+ throw new Exception("Invalid JID: @ but no node");
+ }
+ }
+
+ // Length limits per http://xmpp.org/rfcs/rfc3920.html#addressing
+ if ($node !== null) {
+ if (strlen($node) > 1023) {
+ throw new Exception("Invalid JID: node too long.");
+ }
+ if (preg_match("/[".$nodeprepchars."]/u", $node)) {
+ throw new Exception("Invalid JID node '$node'");
+ }
+ }
+
+ if (strlen($domain) > 1023) {
+ throw new Exception("Invalid JID: domain too long.");
+ }
+ if (!common_valid_domain($domain)) {
+ throw new Exception("Invalid JID domain name '$domain'");
+ }
+
+ if ($resource !== null) {
+ if (strlen($resource) > 1023) {
+ throw new Exception("Invalid JID: resource too long.");
+ }
+ if (preg_match("/[".$chars."]/u", $resource)) {
+ throw new Exception("Invalid JID resource '$resource'");
+ }
+ }
+
+ return array('node' => is_null($node) ? null : mb_strtolower($node),
+ 'domain' => is_null($domain) ? null : mb_strtolower($domain),
+ 'resource' => $resource);
+ }
+
+ /**
+ * Checks whether a string is a syntactically valid Jabber ID (JID),
+ * either with or without a resource.
+ *
+ * Note that a bare domain can be a valid JID.
+ *
+ * @param string $jid string to check
+ * @param bool $check_domain whether we should validate that domain...
+ *
+ * @return boolean whether the string is a valid JID
+ */
+ protected function validateFullJid($jid, $check_domain=false)
+ {
+ try {
+ $parts = $this->splitJid($jid);
+ if ($check_domain) {
+ if (!$this->checkDomain($parts['domain'])) {
+ return false;
+ }
+ }
+ return $parts['resource'] !== ''; // missing or present; empty ain't kosher
+ } catch (Exception $e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether a string is a syntactically valid base Jabber ID (JID).
+ * A base JID won't include a resource specifier on the end; since we
+ * take it off when reading input we can't really use them reliably
+ * to direct outgoing messages yet (sorry guys!)
+ *
+ * Note that a bare domain can be a valid JID.
+ *
+ * @param string $jid string to check
+ * @param bool $check_domain whether we should validate that domain...
+ *
+ * @return boolean whether the string is a valid JID
+ */
+ protected function validateBaseJid($jid, $check_domain=false)
+ {
+ try {
+ $parts = $this->splitJid($jid);
+ if ($check_domain) {
+ if (!$this->checkDomain($parts['domain'])) {
+ return false;
+ }
+ }
+ return ($parts['resource'] === null); // missing; empty ain't kosher
+ } catch (Exception $e) {
+ return false;
+ }
+ }
+
+ /**
+ * Normalizes a Jabber ID for comparison, dropping the resource component if any.
+ *
+ * @param string $jid JID to check
+ * @param bool $check_domain if true, reject if the domain isn't findable
+ *
+ * @return string an equivalent JID in normalized (lowercase) form
+ */
+
+ function normalize($jid)
+ {
+ try {
+ $parts = $this->splitJid($jid);
+ if ($parts['node'] !== null) {
+ return $parts['node'] . '@' . $parts['domain'];
+ } else {
+ return $parts['domain'];
+ }
+ } catch (Exception $e) {