+
+ /**
+ * Determine which notice, if any, a new notice is in reply to.
+ *
+ * For conversation tracking, we try to see where this notice fits
+ * in the tree. Rough algorithm is:
+ *
+ * if (reply_to is set and valid) {
+ * return reply_to;
+ * } else if ((source not API or Web) and (content starts with "T NAME" or "@name ")) {
+ * return ID of last notice by initial @name in content;
+ * }
+ *
+ * Note that all @nickname instances will still be used to save "reply" records,
+ * so the notice shows up in the mentioned users' "replies" tab.
+ *
+ * @param integer $reply_to ID passed in by Web or API
+ * @param integer $profile_id ID of author
+ * @param string $source Source tag, like 'web' or 'gwibber'
+ * @param string $content Final notice content
+ *
+ * @return integer ID of replied-to notice, or null for not a reply.
+ */
+
+ static function getReplyTo($reply_to, $profile_id, $source, $content)
+ {
+ static $lb = array('xmpp', 'mail', 'sms', 'omb');
+
+ // If $reply_to is specified, we check that it exists, and then
+ // return it if it does
+
+ if (!empty($reply_to)) {
+ $reply_notice = Notice::staticGet('id', $reply_to);
+ if (!empty($reply_notice)) {
+ return $reply_to;
+ }
+ }
+
+ // If it's not a "low bandwidth" source (one where you can't set
+ // a reply_to argument), we return. This is mostly web and API
+ // clients.
+
+ if (!in_array($source, $lb)) {
+ return null;
+ }
+
+ // Is there an initial @ or T?
+
+ if (preg_match('/^T ([A-Z0-9]{1,64}) /', $content, $match) ||
+ preg_match('/^@([a-z0-9]{1,64})\s+/', $content, $match)) {
+ $nickname = common_canonical_nickname($match[1]);
+ } else {
+ return null;
+ }
+
+ // Figure out who that is.
+
+ $sender = Profile::staticGet('id', $profile_id);
+ $recipient = common_relative_profile($sender, $nickname, common_sql_now());
+
+ if (empty($recipient)) {
+ return null;
+ }
+
+ // Get their last notice
+
+ $last = $recipient->getCurrentNotice();
+
+ if (!empty($last)) {
+ return $last->id;
+ }
+ }