| Index: chrome/browser/sync/notifier/communicator/mailbox.cc | 
| =================================================================== | 
| --- chrome/browser/sync/notifier/communicator/mailbox.cc	(revision 46353) | 
| +++ chrome/browser/sync/notifier/communicator/mailbox.cc	(working copy) | 
| @@ -1,675 +0,0 @@ | 
| -// Copyright (c) 2009 The Chromium Authors. All rights reserved. | 
| -// Use of this source code is governed by a BSD-style license that can be | 
| -// found in the LICENSE file. | 
| - | 
| -#include "chrome/browser/sync/notifier/communicator/mailbox.h" | 
| - | 
| -#include <assert.h> | 
| -#include <stdlib.h> | 
| - | 
| -#include <stack> | 
| -#include <vector> | 
| - | 
| -#include "chrome/browser/sync/notifier/base/string.h" | 
| -#include "chrome/browser/sync/notifier/base/utils.h" | 
| -#include "chrome/browser/sync/notifier/communicator/xml_parse_helpers.h" | 
| -#include "talk/base/basictypes.h" | 
| -#include "talk/base/common.h" | 
| -#include "talk/base/stringutils.h" | 
| -#include "talk/xmllite/xmlelement.h" | 
| -#include "talk/xmpp/constants.h" | 
| - | 
| -namespace notifier { | 
| - | 
| -// Labels are a list of strings seperated by a '|' character. The '|' character | 
| -// is escaped with a backslash ('\\') and the backslash is also escaped with a | 
| -// backslash. | 
| -static void ParseLabelSet(const std::string& text, | 
| -                          MessageThread::StringSet* labels) { | 
| -  const char* input_cur = text.c_str(); | 
| -  const char* input_end = input_cur + text.size(); | 
| -  char* result = new char[text.size() + 1]; | 
| -  char* next_write = result; | 
| - | 
| -  while (input_cur < input_end) { | 
| -    if (*input_cur == '|') { | 
| -      if (next_write != result) { | 
| -        *next_write = '\0'; | 
| -        labels->insert(std::string(result)); | 
| -        next_write = result; | 
| -      } | 
| -      input_cur++; | 
| -      continue; | 
| -    } | 
| - | 
| -    if (*input_cur == '\\') { | 
| -      // Skip a character in the input and break if we are at the end. | 
| -      input_cur++; | 
| -      if (input_cur >= input_end) | 
| -        break; | 
| -    } | 
| -    *next_write = *input_cur; | 
| -    next_write++; | 
| -    input_cur++; | 
| -  } | 
| - | 
| -  if (next_write != result) { | 
| -    *next_write = '\0'; | 
| -    labels->insert(std::string(result)); | 
| -  } | 
| - | 
| -  delete [] result; | 
| -} | 
| - | 
| -// ----------------------------------------------------------------------------- | 
| - | 
| -std::string MailAddress::safe_name() const { | 
| -  if (!name().empty()) { | 
| -    return name(); | 
| -  } | 
| - | 
| -  if (!address().empty()) { | 
| -    size_t at = address().find('@'); | 
| -    if (at == std::string::npos) { | 
| -      return address(); | 
| -    } | 
| - | 
| -    if (at != 0) { | 
| -      return address().substr(0, at); | 
| -    } | 
| -  } | 
| - | 
| -  return std::string("(unknown)"); | 
| -} | 
| - | 
| -// ----------------------------------------------------------------------------- | 
| -MessageThread::~MessageThread() { | 
| -  Clear(); | 
| -} | 
| - | 
| -void MessageThread::Clear() { | 
| -  delete labels_; | 
| -  labels_ = NULL; | 
| - | 
| -  delete senders_; | 
| -  senders_ = NULL; | 
| -} | 
| - | 
| -MessageThread& MessageThread::operator=(const MessageThread& r) { | 
| -  if (&r != this) { | 
| -    Clear(); | 
| -    // Copy everything. | 
| -    r.AssertValid(); | 
| -    thread_id_ = r.thread_id_; | 
| -    date64_ = r.date64_; | 
| -    message_count_ = r.message_count_; | 
| -    personal_level_ = r.personal_level_; | 
| -    subject_ = r.subject_; | 
| -    snippet_ = r.snippet_; | 
| - | 
| -    if (r.labels_) | 
| -      labels_ = new StringSet(*r.labels_); | 
| -    else | 
| -      labels_ = new StringSet; | 
| -    if (r.senders_) | 
| -      senders_ = new MailSenderList(*r.senders_); | 
| -    else | 
| -      senders_ = new MailSenderList; | 
| -  } | 
| -  AssertValid(); | 
| -  return *this; | 
| -} | 
| - | 
| -MessageThread* MessageThread::CreateFromXML( | 
| -    const buzz::XmlElement* src) { | 
| -  MessageThread* info = new MessageThread(); | 
| -  if (!info || !info->InitFromXml(src)) { | 
| -    delete info; | 
| -    return NULL; | 
| -  } | 
| -  return info; | 
| -} | 
| - | 
| -// Init from a chunk of XML. | 
| -bool MessageThread::InitFromXml(const buzz::XmlElement* src) { | 
| -  labels_ = new StringSet; | 
| -  senders_ = new MailSenderList; | 
| - | 
| -  if (src->Name() != buzz::kQnMailThreadInfo) | 
| -    return false; | 
| - | 
| -  if (!ParseInt64Attr(src, buzz::kQnMailTid, &thread_id_)) | 
| -    return false; | 
| -  if (!ParseInt64Attr(src, buzz::kQnMailDate, &date64_)) | 
| -    return false; | 
| -  if (!ParseIntAttr(src, buzz::kQnMailMessages, &message_count_)) | 
| -    return false; | 
| -  if (!ParseIntAttr(src, buzz::kQnMailParticipation, &personal_level_)) | 
| -    return false; | 
| - | 
| -  const buzz::XmlElement* senders = src->FirstNamed(buzz::kQnMailSenders); | 
| -  if (!senders) | 
| -    return false; | 
| -  for (const buzz::XmlElement* child = senders->FirstElement(); | 
| -       child != NULL; | 
| -       child = child->NextElement()) { | 
| -    if (child->Name() != buzz::kQnMailSender) | 
| -      continue; | 
| -    std::string address; | 
| -    if (!ParseStringAttr(child, buzz::kQnMailAddress, &address)) | 
| -      continue; | 
| -    std::string name; | 
| -    ParseStringAttr(child, buzz::kQnMailName, &name); | 
| -    bool originator = false; | 
| -    ParseBoolAttr(child, buzz::kQnMailOriginator, &originator); | 
| -    bool unread = false; | 
| -    ParseBoolAttr(child, buzz::kQnMailUnread, &unread); | 
| - | 
| -    senders_->push_back(MailSender(name, address, unread, originator)); | 
| -  } | 
| - | 
| -  const buzz::XmlElement* labels = src->FirstNamed(buzz::kQnMailLabels); | 
| -  if (!labels) | 
| -    return false; | 
| -  ParseLabelSet(labels->BodyText(), labels_); | 
| - | 
| -  const buzz::XmlElement* subject = src->FirstNamed(buzz::kQnMailSubject); | 
| -  if (!subject) | 
| -    return false; | 
| -  subject_ = subject->BodyText(); | 
| - | 
| -  const buzz::XmlElement* snippet = src->FirstNamed(buzz::kQnMailSnippet); | 
| -  if (!snippet) | 
| -    return false; | 
| -  snippet_ = snippet->BodyText(); | 
| - | 
| -  AssertValid(); | 
| -  return true; | 
| -} | 
| - | 
| -bool MessageThread::starred() const { | 
| -  return (labels_->find("^t") != labels_->end()); | 
| -} | 
| - | 
| -bool MessageThread::unread() const { | 
| -  return (labels_->find("^u") != labels_->end()); | 
| -} | 
| - | 
| -#if defined(DEBUG) | 
| -// Non-debug version is inline and empty. | 
| -void MessageThread::AssertValid() const { | 
| -  assert(thread_id_ != 0); | 
| -  assert(senders_ != NULL); | 
| -  // In some (odd) cases, gmail may send email with no sender. | 
| -  // assert(!senders_->empty()); | 
| -  assert(message_count_ > 0); | 
| -  assert(labels_ != NULL); | 
| -} | 
| -#endif | 
| - | 
| -MailBox* MailBox::CreateFromXML(const buzz::XmlElement* src) { | 
| -  MailBox* mail_box = new MailBox(); | 
| -  if (!mail_box || !mail_box->InitFromXml(src)) { | 
| -    delete mail_box; | 
| -    return NULL; | 
| -  } | 
| -  return mail_box; | 
| -} | 
| - | 
| -// Init from a chunk of XML. | 
| -bool MailBox::InitFromXml(const buzz::XmlElement* src) { | 
| -  if (src->Name() != buzz::kQnMailBox) | 
| -    return false; | 
| - | 
| -  if (!ParseIntAttr(src, buzz::kQnMailTotalMatched, &mailbox_size_)) | 
| -    return false; | 
| - | 
| -  estimate_ = false; | 
| -  ParseBoolAttr(src, buzz::kQnMailTotalEstimate, &estimate_); | 
| - | 
| -  first_index_ = 0; | 
| -  ParseIntAttr(src, buzz::kQnMailFirstIndex, &first_index_); | 
| - | 
| -  result_time_ = 0; | 
| -  ParseInt64Attr(src, buzz::kQnMailResultTime, &result_time_); | 
| - | 
| -  highest_thread_id_ = 0; | 
| - | 
| -  const buzz::XmlElement* thread_element = src->FirstNamed(buzz::kQnMailThreadInfo); | 
| -  while (thread_element) { | 
| -    MessageThread* thread = MessageThread::CreateFromXML(thread_element); | 
| -    if (thread) { | 
| -      if (thread->thread_id() > highest_thread_id_) | 
| -        highest_thread_id_ = thread->thread_id(); | 
| -      threads_.push_back(MessageThreadPointer(thread)); | 
| -    } | 
| -    thread_element = thread_element->NextNamed(buzz::kQnMailThreadInfo); | 
| -  } | 
| -  return true; | 
| -} | 
| - | 
| -const size_t kMaxShortnameLength = 12; | 
| - | 
| -// Tip: If you extend this list of chars, do not include '-'. | 
| -const char name_delim[] = " ,.:;\'\"()[]{}<>*@"; | 
| - | 
| -class SenderFormatter { | 
| - public: | 
| -  // sender should not be deleted while this class is in use. | 
| -  SenderFormatter(const MailSender& sender, | 
| -                  const std::string& me_address) | 
| -      : sender_(sender), | 
| -        visible_(false), | 
| -        short_format_(true), | 
| -        space_(kMaxShortnameLength) { | 
| -    me_ = talk_base::ascicmp(me_address.c_str(), | 
| -                             sender.address().c_str()) == 0; | 
| -  } | 
| - | 
| -  bool visible() const { | 
| -    return visible_; | 
| -  } | 
| - | 
| -  bool is_unread() const { | 
| -    return sender_.unread(); | 
| -  } | 
| - | 
| -  const std::string name() const { | 
| -    return name_; | 
| -  } | 
| - | 
| -  void set_short_format(bool short_format) { | 
| -    short_format_ = short_format; | 
| -    UpdateName(); | 
| -  } | 
| - | 
| -  void set_visible(bool visible) { | 
| -    visible_ = visible; | 
| -    UpdateName(); | 
| -  } | 
| - | 
| -  void set_space(size_t space) { | 
| -    space_ = space; | 
| -    UpdateName(); | 
| -  } | 
| - | 
| - private: | 
| -  // Attempt to shorten to the first word in a person's name We could revisit | 
| -  // and do better at international punctuation, but this is what cricket did, | 
| -  // and it should be removed soon when gmail does the notification instead of | 
| -  // us forming it on the client. | 
| -  static void ShortenName(std::string* name) { | 
| -    size_t start = name->find_first_not_of(name_delim); | 
| -    if (start != std::string::npos && start > 0) { | 
| -      name->erase(0, start); | 
| -    } | 
| -    start = name->find_first_of(name_delim); | 
| -    if (start != std::string::npos) { | 
| -      name->erase(start); | 
| -    } | 
| -  } | 
| - | 
| -  void UpdateName() { | 
| -    // Update the name if is going to be used. | 
| -    if (!visible_) { | 
| -      return; | 
| -    } | 
| - | 
| -    if (me_) { | 
| -      name_ = "me"; | 
| -      return; | 
| -    } | 
| - | 
| -    if (sender_.name().empty() && sender_.address().empty()) { | 
| -      name_ = ""; | 
| -      return; | 
| -    } | 
| - | 
| -    name_ = sender_.name(); | 
| -    // Handle the case of no name or a name looks like an email address. When | 
| -    // mail is sent to "Quality@example.com" <quality-team@example.com>, we | 
| -    // shouldn't show "Quality@example.com" as the name. Instead, use the email | 
| -    // address (without the @...) | 
| -    if (name_.empty() || name_.find_first_of("@") != std::string::npos) { | 
| -      name_ = sender_.address(); | 
| -      size_t at_index = name_.find_first_of("@"); | 
| -      if (at_index != std::string::npos) { | 
| -        name_.erase(at_index); | 
| -      } | 
| -    } else if (short_format_) { | 
| -      ShortenName(&name_); | 
| -    } | 
| - | 
| -    if (name_.empty()) { | 
| -      name_ = "(unknown)"; | 
| -    } | 
| - | 
| -    // Abbreviate if too long. | 
| -    if (name_.size() > space_) { | 
| -      name_.replace(space_ - 1, std::string::npos, "."); | 
| -    } | 
| -  } | 
| - | 
| -  const MailSender& sender_; | 
| -  std::string name_; | 
| -  bool visible_; | 
| -  bool short_format_; | 
| -  size_t space_; | 
| -  bool me_; | 
| -  DISALLOW_COPY_AND_ASSIGN(SenderFormatter); | 
| -}; | 
| - | 
| -const char kNormalSeparator[] = ", "; | 
| -const char kEllidedSeparator[] = " .."; | 
| - | 
| -std::string FormatName(const std::string& name, bool bold) { | 
| -  std::string formatted_name; | 
| -  if (bold) { | 
| -    formatted_name.append("<b>"); | 
| -  } | 
| -  formatted_name.append(HtmlEncode(name)); | 
| -  if (bold) { | 
| -    formatted_name.append("</b>"); | 
| -  } | 
| -  return formatted_name; | 
| -} | 
| - | 
| -class SenderFormatterList { | 
| - public: | 
| -  // sender_list must not be deleted while this class is being used. | 
| -  SenderFormatterList(const MailSenderList& sender_list, | 
| -                      const std::string& me_address) | 
| -      : state_(INITIAL_STATE), | 
| -        are_any_read_(false), | 
| -        index_(-1), | 
| -        first_unread_index_(-1) { | 
| -    // Add all read messages. | 
| -    const MailSender* originator = NULL; | 
| -    bool any_unread = false; | 
| -    for (size_t i = 0; i < sender_list.size(); ++i) { | 
| -      if (sender_list[i].originator()) { | 
| -        originator = &sender_list[i]; | 
| -      } | 
| -      if (sender_list[i].unread()) { | 
| -        any_unread = true; | 
| -        continue; | 
| -      } | 
| -      are_any_read_ = true; | 
| -      if (!sender_list[i].originator()) { | 
| -        senders_.push_back(new SenderFormatter(sender_list[i], | 
| -                                               me_address)); | 
| -      } | 
| -    } | 
| - | 
| -    // There may not be an orignator (if there no senders). | 
| -    if (originator) { | 
| -      senders_.insert(senders_.begin(), new SenderFormatter(*originator, | 
| -                                                            me_address)); | 
| -    } | 
| - | 
| -    // Add all unread messages. | 
| -    if (any_unread) { | 
| -      // It should be rare, but there may be cases when all of the senders | 
| -      // appear to have read the message. | 
| -      first_unread_index_ = is_first_unread() ? 0 : senders_.size(); | 
| -      for (size_t i = 0; i < sender_list.size(); ++i) { | 
| -        if (!sender_list[i].unread()) { | 
| -          continue; | 
| -        } | 
| -        // Don't add the originator if it is already at the start of the | 
| -        // "unread" list. | 
| -        if (sender_list[i].originator() && is_first_unread()) { | 
| -          continue; | 
| -        } | 
| -        senders_.push_back(new SenderFormatter(sender_list[i], me_address)); | 
| -      } | 
| -    } | 
| -  } | 
| - | 
| -  ~SenderFormatterList() { | 
| -    CleanupSequence(&senders_); | 
| -  } | 
| - | 
| -  std::string GetHtml(int space) { | 
| -    index_ = -1; | 
| -    state_ = INITIAL_STATE; | 
| -    while (!added_.empty()) { | 
| -      added_.pop(); | 
| -    } | 
| - | 
| -    // If there is only one sender, let it take up all of the space. | 
| -    if (senders_.size() == 1) { | 
| -      senders_[0]->set_space(space); | 
| -      senders_[0]->set_short_format(false); | 
| -    } | 
| - | 
| -    int length = 1; | 
| -    // Add as many senders as we can in the given space. Computes the visible | 
| -    // length at each iteration, but does not construct the actual html. | 
| -    while (length < space && AddNextSender()) { | 
| -      int new_length = ConstructHtml(is_first_unread(), NULL); | 
| -      // Remove names to avoid truncating | 
| -      // * if there will be at least 2 left or | 
| -      // * if the spacing <= 2 characters per sender and there | 
| -      //   is at least one left. | 
| -      if ((new_length > space && | 
| -           (visible_count() > 2 || | 
| -            (ComputeSpacePerSender(space) <= 2 && visible_count() > 1)))) { | 
| -        RemoveLastAddedSender(); | 
| -        break; | 
| -      } | 
| -      length = new_length; | 
| -    } | 
| - | 
| -    if (length > space) { | 
| -      int max = ComputeSpacePerSender(space); | 
| -      for (size_t i = 0; i < senders_.size(); ++i) { | 
| -        if (senders_[i]->visible()) { | 
| -          senders_[i]->set_space(max); | 
| -        } | 
| -      } | 
| -    } | 
| - | 
| -    // Now construct the actual html. | 
| -    std::string html_list; | 
| -    length = ConstructHtml(is_first_unread(), &html_list); | 
| -    if (length > space) { | 
| -      LOG(LS_WARNING) << "LENGTH: " << length << " exceeds " | 
| -                      << space << " " << html_list; | 
| -    } | 
| -    return html_list; | 
| -  } | 
| - | 
| - private: | 
| -  int ComputeSpacePerSender(int space) const { | 
| -    // Why the "- 2"? To allow for the " .. " which may occur after the names, | 
| -    // and no matter what always allow at least 2 characters per sender. | 
| -    return talk_base::_max<int>(space / visible_count() - 2, 2); | 
| -  } | 
| - | 
| -  // Finds the next sender that should be added to the "from" list and sets it | 
| -  // to visible. | 
| -  // | 
| -  // This method may be called until it returns false or until | 
| -  // RemoveLastAddedSender is called. | 
| -  bool AddNextSender() { | 
| -    // The progression is: | 
| -    //   1. Add the person who started the thread, which is the first message. | 
| -    //   2. Add the first unread message (unless it has already been added). | 
| -    //   3. Add the last message (unless it has already been added). | 
| -    //   4. Add the message that is just before the last message processed | 
| -    //      (unless it has already been added). | 
| -    //      If there is no message (i.e. at index -1), return false. | 
| -    // | 
| -    // Typically, this method is called until it returns false or all of the | 
| -    // space available is used. | 
| -    switch (state_) { | 
| -      case INITIAL_STATE: | 
| -        state_ = FIRST_MESSAGE; | 
| -        index_ = 0; | 
| -        // If the server behaves odd and doesn't send us any senders, do | 
| -        // something graceful. | 
| -        if (senders_.size() == 0) { | 
| -          return false; | 
| -        } | 
| -        break; | 
| - | 
| -      case FIRST_MESSAGE: | 
| -        if (first_unread_index_ >= 0) { | 
| -          state_ = FIRST_UNREAD_MESSAGE; | 
| -          index_ = first_unread_index_; | 
| -          break; | 
| -        } | 
| -        // Fall through. | 
| -      case FIRST_UNREAD_MESSAGE: | 
| -        state_ = LAST_MESSAGE; | 
| -        index_ = senders_.size() - 1; | 
| -        break; | 
| - | 
| -      case LAST_MESSAGE: | 
| -      case PREVIOUS_MESSAGE: | 
| -        state_ = PREVIOUS_MESSAGE; | 
| -        index_--; | 
| -        break; | 
| - | 
| -      case REMOVED_MESSAGE: | 
| -      default: | 
| -        ASSERT(false); | 
| -        return false; | 
| -    } | 
| - | 
| -    if (index_ < 0) { | 
| -      return false; | 
| -    } | 
| - | 
| -    if (!senders_[index_]->visible()) { | 
| -      added_.push(index_); | 
| -      senders_[index_]->set_visible(true); | 
| -    } | 
| -    return true; | 
| -  } | 
| - | 
| -  // Makes the last added sender not visible. | 
| -  // | 
| -  // May be called while visible_count() > 0. | 
| -  void RemoveLastAddedSender() { | 
| -    state_ = REMOVED_MESSAGE; | 
| -    int index = added_.top(); | 
| -    added_.pop(); | 
| -    senders_[index]->set_visible(false); | 
| -  } | 
| - | 
| -  // Constructs the html of the SenderList and returns the length of the | 
| -  // visible text. | 
| -  // | 
| -  // The algorithm simply walks down the list of Senders, appending the html | 
| -  // for each visible sender, and adding ellipsis or commas in between, | 
| -  // whichever is appropriate. | 
| -  // | 
| -  // html Filled with html.  Maybe NULL if the html doesn't need to be | 
| -  //      constructed yet (useful for simply determining the length of the | 
| -  //      visible text). | 
| -  // | 
| -  // returns The approximate visible length of the html. | 
| -  int ConstructHtml(bool first_is_unread, | 
| -                    std::string* html) const { | 
| -    if (senders_.empty()) { | 
| -      return 0; | 
| -    } | 
| - | 
| -    int length = 0; | 
| - | 
| -    // The first is always visible. | 
| -    const SenderFormatter* sender = senders_[0]; | 
| -    const std::string& originator_name = sender->name(); | 
| -    length += originator_name.length(); | 
| -    if (html) { | 
| -      html->append(FormatName(originator_name, first_is_unread)); | 
| -    } | 
| - | 
| -    bool elided = false; | 
| -    const char* between = ""; | 
| -    for (size_t i = 1; i < senders_.size(); i++) { | 
| -      sender = senders_[i]; | 
| - | 
| -      if (sender->visible()) { | 
| -        // Handle the separator. | 
| -        between = elided ? " " : kNormalSeparator; | 
| -        // Ignore the , for length because it is so narrow, so in both cases | 
| -        // above the space is the only things that counts for spaces. | 
| -        length++; | 
| - | 
| -        // Handle the name. | 
| -        const std::string name = sender->name(); | 
| -        length += name.size(); | 
| - | 
| -        // Construct the html. | 
| -        if (html) { | 
| -          html->append(between); | 
| -          html->append(FormatName(name, sender->is_unread())); | 
| -        } | 
| -        elided = false; | 
| -      } else if (!elided) { | 
| -        between = kEllidedSeparator; | 
| -        length += 2;  // ".." is narrow. | 
| -        if (html) { | 
| -          html->append(between); | 
| -        } | 
| -        elided = true; | 
| -      } | 
| -    } | 
| -    return length; | 
| -  } | 
| - | 
| -  bool is_first_unread() const { | 
| -    return !are_any_read_; | 
| -  } | 
| - | 
| -  size_t visible_count() const { | 
| -    return added_.size(); | 
| -  } | 
| - | 
| -  enum MessageState { | 
| -    INITIAL_STATE, | 
| -    FIRST_MESSAGE, | 
| -    FIRST_UNREAD_MESSAGE, | 
| -    LAST_MESSAGE, | 
| -    PREVIOUS_MESSAGE, | 
| -    REMOVED_MESSAGE, | 
| -  }; | 
| - | 
| -  // What state we were in during the last "stateful" function call. | 
| -  MessageState state_; | 
| -  bool are_any_read_; | 
| -  std::vector<SenderFormatter*> senders_; | 
| -  std::stack<int> added_; | 
| -  int index_; | 
| -  int first_unread_index_; | 
| -  DISALLOW_COPY_AND_ASSIGN(SenderFormatterList); | 
| -}; | 
| - | 
| - | 
| -std::string GetSenderHtml(const MailSenderList& sender_list, | 
| -                          int message_count, | 
| -                          const std::string& me_address, | 
| -                          int space) { | 
| -  // There has to be at least 9 spaces to show something reasonable. | 
| -  ASSERT(space >= 10); | 
| -  std::string count_html; | 
| -  if (message_count > 1) { | 
| -    std::string count(IntToString(message_count)); | 
| -    space -= (count.size()); | 
| -    count_html.append(" ("); | 
| -    count_html.append(count); | 
| -    count_html.append(")"); | 
| -    // Reduce space due to parenthesis and  . | 
| -    space -= 2; | 
| -  } | 
| - | 
| -  SenderFormatterList senders(sender_list, me_address); | 
| -  std::string html_list(senders.GetHtml(space)); | 
| -  html_list.append(count_html); | 
| -  return html_list; | 
| -} | 
| - | 
| -}  // namespace notifier | 
|  |