void THeaderView::InitEmailCompletion() { // get boot volume BVolume volume; BVolumeRoster().GetBootVolume(&volume); BQuery query; query.SetVolume(&volume); query.SetPredicate("META:email=**"); // Due to R5 BFS bugs, you need two stars, META:email=** for the query. // META:email="*" will just return one entry and stop, same with // META:email=* and a few other variations. Grumble. query.Fetch(); entry_ref ref; while (query.GetNextRef (&ref) == B_OK) { BNode file; if (file.SetTo(&ref) == B_OK) { // Add the e-mail address as an auto-complete string. BString email; if (file.ReadAttrString("META:email", &email) >= B_OK) fEmailList.AddChoice(email.String()); // Also add the quoted full name as an auto-complete string. Can't // do unquoted since auto-complete isn't that smart, so the user // will have to type a quote mark if he wants to select someone by // name. BString fullName; if (file.ReadAttrString("META:name", &fullName) >= B_OK) { if (email.FindFirst('<') < 0) { email.ReplaceAll('>', '_'); email.Prepend("<"); email.Append(">"); } fullName.ReplaceAll('\"', '_'); fullName.Prepend("\""); fullName << "\" " << email; fEmailList.AddChoice(fullName.String()); } // support for 3rd-party People apps. Looks like a job for // multiple keyword (so you can have several e-mail addresses in // one attribute, perhaps comma separated) indices! Which aren't // yet in BFS. for (int16 i = 2; i < 6; i++) { char attr[16]; sprintf(attr, "META:email%d", i); if (file.ReadAttrString(attr, &email) >= B_OK) fEmailList.AddChoice(email.String()); } } } }
status_t write_read_attr(BNode& node, read_flags flag) { if (node.WriteAttr(B_MAIL_ATTR_READ, B_INT32_TYPE, 0, &flag, sizeof(int32)) < 0) return B_ERROR; #if R5_COMPATIBLE // manage the status string only if it currently has a "read" status BString currentStatus; if (node.ReadAttrString(B_MAIL_ATTR_STATUS, ¤tStatus) == B_OK) { if (currentStatus.ICompare("New") != 0 && currentStatus.ICompare("Read") != 0 && currentStatus.ICompare("Seen") != 0) return B_OK; } const char* statusString = (flag == B_READ) ? "Read" : (flag == B_SEEN) ? "Seen" : "New"; if (node.WriteAttr(B_MAIL_ATTR_STATUS, B_STRING_TYPE, 0, statusString, strlen(statusString)) < 0) return B_ERROR; #endif return B_OK; }
status_t StyledEditView::GetStyledText(BPositionIO* stream) { fSuppressChanges = true; status_t result = BTranslationUtils::GetStyledText(stream, this, fEncoding.String()); fSuppressChanges = false; if (result != B_OK) return result; BNode* node = dynamic_cast<BNode*>(stream); if (node != NULL) { // get encoding if (node->ReadAttrString("be:encoding", &fEncoding) != B_OK) { // try to read as "int32" int32 encoding; ssize_t bytesRead = node->ReadAttr("be:encoding", B_INT32_TYPE, 0, &encoding, sizeof(encoding)); if (bytesRead == (ssize_t)sizeof(encoding)) { if (encoding == 65535) { fEncoding = "UTF-8"; } else { const BCharacterSet* characterSet = BCharacterSetRoster::GetCharacterSetByConversionID(encoding); if (characterSet != NULL) fEncoding = characterSet->GetName(); } } } // TODO: move those into BTranslationUtils::GetStyledText() as well? // restore alignment int32 align; ssize_t bytesRead = node->ReadAttr("alignment", 0, 0, &align, sizeof(align)); if (bytesRead == (ssize_t)sizeof(align)) SetAlignment((alignment)align); // restore wrapping bool wrap; bytesRead = node->ReadAttr("wrap", 0, 0, &wrap, sizeof(wrap)); if (bytesRead == (ssize_t)sizeof(wrap)) { SetWordWrap(wrap); if (wrap == false) { BRect textRect; textRect = Bounds(); textRect.OffsetTo(B_ORIGIN); textRect.InsetBy(TEXT_INSET, TEXT_INSET); // the width comes from stylededit R5. TODO: find a better way textRect.SetRightBottom(BPoint(1500.0, textRect.RightBottom().y)); SetTextRect(textRect); } } } return result; }
uint32 IMAPFolder::_ReadUniqueID(BNode& node) const { // For compatibility we must assume that the UID is stored as a string BString string; if (node.ReadAttrString(kUIDAttribute, &string) != B_OK) return 0; return strtoul(string.String(), NULL, 0); }
entry_ref* TaskFS::FileForId(Task *theTask) { //**scan through all files for the ID or shell we do a querry?? BString fileID; entry_ref *ref; BNode theNode; while (tasksDir.GetNextRef(ref) == B_OK){ theNode.SetTo(ref); if (theNode.ReadAttrString("META:task_id", &fileID) == B_OK) if (fileID==theTask->ID() && fileID.Length() != 0) return ref; } return NULL; }
status_t IMAPFolder::_MailToIMAPFlags(BNode& node, uint32& flags) { BString mailStatus; status_t status = node.ReadAttrString(B_MAIL_ATTR_STATUS, &mailStatus); if (status != B_OK) return status; flags &= ~(IMAP::kAnswered | IMAP::kSeen); // TODO: add some utility function for this in libmail.so if (mailStatus == "Answered") flags |= IMAP::kAnswered | IMAP::kSeen; else if (mailStatus == "Read") flags |= IMAP::kSeen; else if (mailStatus == "Starred") flags |= IMAP::kFlagged | IMAP::kSeen; return B_OK; }
status_t read_read_attr(BNode& node, read_flags& flag) { if (node.ReadAttr(B_MAIL_ATTR_READ, B_INT32_TYPE, 0, &flag, sizeof(int32)) == sizeof(int32)) return B_OK; #if R5_COMPATIBLE BString statusString; if (node.ReadAttrString(B_MAIL_ATTR_STATUS, &statusString) == B_OK) { if (statusString.ICompare("New")) flag = B_UNREAD; else flag = B_READ; return B_OK; } #endif return B_ERROR; }
void THeaderView::InitGroupCompletion() { // get boot volume BVolume volume; BVolumeRoster().GetBootVolume(&volume); // Build a list of all unique groups and the addresses they expand to. BQuery query; query.SetVolume(&volume); query.SetPredicate("META:group=**"); query.Fetch(); map<BString *, BString *, CompareBStrings> groupMap; entry_ref ref; BNode file; while (query.GetNextRef(&ref) == B_OK) { if (file.SetTo(&ref) != B_OK) continue; BString groups; if (file.ReadAttrString("META:group", &groups) < B_OK || groups.Length() == 0) continue; BString address; file.ReadAttrString("META:email", &address); // avoid adding an empty address if (address.Length() == 0) continue; char *group = groups.LockBuffer(groups.Length()); char *next = strchr(group, ','); for (;;) { if (next) *next = 0; while (*group && *group == ' ') group++; BString *groupString = new BString(group); BString *addressListString = NULL; // nobody is in this group yet, start it off if (groupMap[groupString] == NULL) { addressListString = new BString(*groupString); addressListString->Append(" "); groupMap[groupString] = addressListString; } else { addressListString = groupMap[groupString]; addressListString->Append(", "); delete groupString; } // Append the user's address to the end of the string with the // comma separated list of addresses. If not present, add the // < and > brackets around the address. if (address.FindFirst ('<') < 0) { address.ReplaceAll ('>', '_'); address.Prepend ("<"); address.Append(">"); } addressListString->Append(address); if (!next) break; group = next + 1; next = strchr(group, ','); } } map<BString *, BString *, CompareBStrings>::iterator iter; for (iter = groupMap.begin(); iter != groupMap.end();) { BString *group = iter->first; BString *addr = iter->second; fEmailList.AddChoice(addr->String()); ++iter; groupMap.erase(group); delete group; delete addr; } }
void QPopupMenu::EntryCreated(const entry_ref &ref, ino_t node) { BNode file; if (file.SetTo(&ref) < B_OK) return; // Make sure the pop-up menu is ready for additions. Need a bunch of // groups at the top, a divider line, and miscellaneous people added below // the line. int32 items = CountItems(); if (!items) AddSeparatorItem(); // Does the file have a group attribute? OK to have none. BString groups; const char *kNoGroup = "NoGroup!"; file.ReadAttrString("META:group", &groups); if (groups.Length() <= 0) groups = kNoGroup; // Add the e-mail address to the all people group. Then add it to all the // group menus that it exists in (based on the comma separated list of // groups from the People file), optionally making the group menu if it // doesn't exist. If it's in the special NoGroup! list, then add it below // the groups. bool allPeopleGroupDone = false; BMenu *groupMenu; do { BString group; if (!allPeopleGroupDone) { // Create the default group for all people, if it doesn't exist yet. group = "All People"; allPeopleGroupDone = true; } else { // Break out the next group from the comma separated string. int32 comma; if ((comma = groups.FindFirst(',')) > 0) { groups.MoveInto(group, 0, comma); groups.Remove(0, 1); } else group.Adopt(groups); } // trim white spaces int32 i = 0; for (i = 0; isspace(group.ByteAt(i)); i++) {} if (i) group.Remove(0, i); for (i = group.Length() - 1; isspace(group.ByteAt(i)); i--) {} group.Truncate(i + 1); groupMenu = NULL; BMenuItem *superItem = NULL; // Corresponding item for group menu. if (group.Length() > 0 && group != kNoGroup) { BMenu *sub; // Look for submenu with label == group name for (int32 i = 0; i < items; i++) { if ((sub = SubmenuAt(i)) != NULL) { superItem = sub->Superitem(); if (!strcmp(superItem->Label(), group.String())) { groupMenu = sub; i++; break; } } } // If no submenu, create one if (!groupMenu) { // Find where it should go (alphabetical) int32 mindex = 0; for (; mindex < fGroups; mindex++) { if (strcmp(ItemAt(mindex)->Label(), group.String()) > 0) break; } groupMenu = new BMenu(group.String()); groupMenu->SetFont(be_plain_font); AddItem(groupMenu, mindex); superItem = groupMenu->Superitem(); superItem->SetMessage(new BMessage(B_SIMPLE_DATA)); if (fTargetHandler) superItem->SetTarget(fTargetHandler); fGroups++; } } BString name; file.ReadAttrString("META:name", &name); BString email; file.ReadAttrString("META:email", &email); if (email.Length() != 0 || name.Length() != 0) AddPersonItem(&ref, node, name, email, NULL, groupMenu, superItem); // support for 3rd-party People apps for (int16 i = 2; i < 6; i++) { char attr[16]; sprintf(attr, "META:email%d", i); if (file.ReadAttrString(attr, &email) >= B_OK && email.Length() > 0) AddPersonItem(&ref, node, name, email, attr, groupMenu, superItem); } } while (groups.Length() > 0); }
/*! Convert the plain text (UTF8) from inSource to plain or styled text in outDestination */ status_t translate_from_text(BPositionIO* source, const char* encoding, bool forceEncoding, BPositionIO* destination, uint32 outType) { if (outType != B_TRANSLATOR_TEXT && outType != B_STYLED_TEXT_FORMAT) return B_BAD_VALUE; // find the length of the text off_t size = source->Seek(0, SEEK_END); if (size < 0) return (status_t)size; if (size > UINT32_MAX && outType == B_STYLED_TEXT_FORMAT) return B_NOT_SUPPORTED; status_t status = source->Seek(0, SEEK_SET); if (status < B_OK) return status; if (outType == B_STYLED_TEXT_FORMAT) { // output styled text headers status = output_headers(destination, (uint32)size); if (status != B_OK) return status; } class MallocBuffer { public: MallocBuffer() : fBuffer(NULL), fSize(0) {} ~MallocBuffer() { free(fBuffer); } void* Buffer() { return fBuffer; } size_t Size() const { return fSize; } status_t Allocate(size_t size) { fBuffer = malloc(size); if (fBuffer != NULL) { fSize = size; return B_OK; } return B_NO_MEMORY; } private: void* fBuffer; size_t fSize; } encodingBuffer; BMallocIO encodingIO; uint32 encodingID = 0; // defaults to UTF-8 or no encoding BNode* node = dynamic_cast<BNode*>(source); if (node != NULL) { // determine encoding, if available const BCharacterSet* characterSet = NULL; bool hasAttribute = false; if (encoding != NULL && !forceEncoding) { BString name; if (node->ReadAttrString("be:encoding", &name) == B_OK) { encoding = name.String(); hasAttribute = true; } else { int32 value; ssize_t bytesRead = node->ReadAttr("be:encoding", B_INT32_TYPE, 0, &value, sizeof(value)); if (bytesRead == (ssize_t)sizeof(value)) { hasAttribute = true; if (value != 65535) characterSet = BCharacterSetRoster::GetCharacterSetByConversionID(value); } } } else { hasAttribute = true; // we don't write the encoding in this case } if (characterSet == NULL && encoding != NULL) characterSet = BCharacterSetRoster::FindCharacterSetByName(encoding); if (characterSet != NULL) { encodingID = characterSet->GetConversionID(); encodingBuffer.Allocate(READ_BUFFER_SIZE * 4); } if (!hasAttribute && encoding != NULL) { // add encoding attribute, so that someone opening the file can // retrieve it for persistance node->WriteAttr("be:encoding", B_STRING_TYPE, 0, encoding, strlen(encoding)); } } off_t outputSize = 0; ssize_t bytesRead; int32 state = 0; // output the actual text part of the data do { uint8 buffer[READ_BUFFER_SIZE]; bytesRead = source->Read(buffer, READ_BUFFER_SIZE); if (bytesRead < B_OK) return bytesRead; if (bytesRead == 0) break; if (encodingBuffer.Size() == 0) { // default, no encoding ssize_t bytesWritten = destination->Write(buffer, bytesRead); if (bytesWritten != bytesRead) { if (bytesWritten < B_OK) return bytesWritten; return B_ERROR; } outputSize += bytesRead; } else { // decode text file to UTF-8 char* pos = (char*)buffer; int32 encodingLength = encodingIO.BufferLength(); int32 bytesLeft = bytesRead; int32 bytes; do { encodingLength = READ_BUFFER_SIZE * 4; bytes = bytesLeft; status = convert_to_utf8(encodingID, pos, &bytes, (char*)encodingBuffer.Buffer(), &encodingLength, &state); if (status < B_OK) return status; ssize_t bytesWritten = destination->Write(encodingBuffer.Buffer(), encodingLength); if (bytesWritten < encodingLength) { if (bytesWritten < B_OK) return bytesWritten; return B_ERROR; } pos += bytes; bytesLeft -= bytes; outputSize += encodingLength; } while (encodingLength > 0 && bytesLeft > 0); } } while (bytesRead > 0); if (outType != B_STYLED_TEXT_FORMAT) return B_OK; if (encodingBuffer.Size() != 0 && size != outputSize) { if (outputSize > UINT32_MAX) return B_NOT_SUPPORTED; // we need to update the header as the decoded text size has changed status = destination->Seek(0, SEEK_SET); if (status == B_OK) status = output_headers(destination, (uint32)outputSize); if (status == B_OK) status = destination->Seek(0, SEEK_END); if (status < B_OK) return status; } // Read file attributes if outputting styled data // and source is a BNode object if (node == NULL) return B_OK; // Try to read styles - we only propagate an error if the actual on-disk // data is likely to be okay const char *kAttrName = "styles"; attr_info info; if (node->GetAttrInfo(kAttrName, &info) != B_OK) return B_OK; if (info.type != B_RAW_TYPE || info.size < 160) { // styles seem to be broken, but since we got the text, // we don't propagate the error return B_OK; } uint8* flatRunArray = new (std::nothrow) uint8[info.size]; if (flatRunArray == NULL) return B_NO_MEMORY; bytesRead = node->ReadAttr(kAttrName, B_RAW_TYPE, 0, flatRunArray, info.size); if (bytesRead != info.size) return B_OK; output_styles(destination, size, flatRunArray, info.size); delete[] flatRunArray; return B_OK; }