use of com.zimbra.cs.mailbox.Contact.Attachment in project zm-mailbox by Zimbra.
the class ParsedContact method init.
private void init(Map<String, ? extends Object> fields, InputStream in) throws ServiceException {
if (fields == null) {
throw ServiceException.INVALID_REQUEST("contact must have fields", null);
}
// Initialized shared stream.
try {
if (in instanceof SharedInputStream) {
sharedStream = in;
} else if (in != null) {
byte[] content = ByteUtil.getContent(in, 1024);
sharedStream = new SharedByteArrayInputStream(content);
}
} catch (IOException e) {
throw MailServiceException.MESSAGE_PARSE_ERROR(e);
}
// Initialize fields.
Map<String, String> map = new HashMap<String, String>();
for (Map.Entry<String, ? extends Object> entry : fields.entrySet()) {
String key = StringUtil.stripControlCharacters(entry.getKey());
String value = null;
if (entry.getValue() instanceof String[]) {
// encode multi value attributes as JSONObject
try {
value = Contact.encodeMultiValueAttr((String[]) entry.getValue());
} catch (JSONException e) {
ZimbraLog.index.warn("Error encoding multi valued attribute " + key, e);
}
} else if (entry.getValue() instanceof String) {
value = StringUtil.stripControlCharacters((String) entry.getValue());
} else if (entry.getValue() instanceof ContactGroup) {
value = ((ContactGroup) entry.getValue()).encode();
}
if (key != null && !key.trim().isEmpty() && !Strings.isNullOrEmpty(value)) {
if (key.length() > ContactConstants.MAX_FIELD_NAME_LENGTH) {
throw ServiceException.INVALID_REQUEST("too big filed name", null);
} else if (value.length() > ContactConstants.MAX_FIELD_VALUE_LENGTH) {
throw MailServiceException.CONTACT_TOO_BIG(ContactConstants.MAX_FIELD_VALUE_LENGTH, value.length());
}
map.put(key, value);
}
}
if (map.isEmpty()) {
throw ServiceException.INVALID_REQUEST("contact must have fields", null);
} else if (map.size() > ContactConstants.MAX_FIELD_COUNT) {
throw ServiceException.INVALID_REQUEST("too many fields", null);
}
contactFields = map;
// Initialize attachments.
if (sharedStream != null) {
InputStream contentStream = null;
try {
// Parse attachments.
contentStream = getContentStream();
contactAttachments = parseBlob(contentStream);
for (Attachment attach : contactAttachments) {
contactFields.remove(attach.getName());
}
initializeSizeAndDigest();
} catch (MessagingException me) {
throw MailServiceException.MESSAGE_PARSE_ERROR(me);
} catch (IOException ioe) {
throw MailServiceException.MESSAGE_PARSE_ERROR(ioe);
} finally {
ByteUtil.closeStream(contentStream);
}
}
}
use of com.zimbra.cs.mailbox.Contact.Attachment in project zm-mailbox by Zimbra.
the class VCard method formatContact.
public static VCard formatContact(Contact con, Collection<String> vcattrs, boolean includeXProps, boolean includeZimbraXProps) {
Map<String, String> fields = con.getFields();
List<Attachment> attachments = con.getAttachments();
List<String> emails = con.getEmailAddresses(DerefGroupMembersOption.NONE);
StringBuilder sb = new StringBuilder();
sb.append("BEGIN:VCARD\r\n");
if (vcattrs == null || vcattrs.contains("VERSION"))
sb.append("VERSION:3.0\r\n");
// FN is a mandatory component of the vCard -- try our best to find or generate one
String fn = fields.get(ContactConstants.A_fullName);
if (vcattrs == null || vcattrs.contains("FN")) {
if (fn == null || fn.trim().equals(""))
try {
fn = con.getFileAsString();
} catch (ServiceException e) {
fn = "";
}
if (fn.trim().equals("") && !emails.isEmpty())
fn = emails.get(0);
if (fn.trim().equals("")) {
String org = fields.get(ContactConstants.A_company);
if (org != null && !org.trim().equals("")) {
fn = org;
}
}
sb.append("FN:").append(vcfEncode(fn)).append("\r\n");
}
if (vcattrs == null || vcattrs.contains("N")) {
StringBuilder nSb = new StringBuilder();
nSb.append(vcfEncode(fields.get(ContactConstants.A_lastName))).append(';').append(vcfEncode(fields.get(ContactConstants.A_firstName))).append(';').append(vcfEncode(fields.get(ContactConstants.A_middleName))).append(';').append(vcfEncode(fields.get(ContactConstants.A_namePrefix))).append(';').append(vcfEncode(fields.get(ContactConstants.A_nameSuffix)));
String n = nSb.toString();
// so, try to avoid that.
if (";;;;".equals(n)) {
n = vcfEncode(fn) + ";;;;";
}
sb.append("N:").append(n).append("\r\n");
}
if (vcattrs == null || vcattrs.contains("NICKNAME"))
encodeField(sb, "NICKNAME", fields.get(ContactConstants.A_nickname));
if (vcattrs == null || vcattrs.contains("PHOTO"))
encodeField(sb, "PHOTO;VALUE=URI", fields.get(ContactConstants.A_image));
if (vcattrs == null || vcattrs.contains("BDAY")) {
String bday = fields.get(ContactConstants.A_birthday);
if (bday != null) {
Date date = DateUtil.parseDateSpecifier(bday);
if (date != null)
sb.append("BDAY;VALUE=date:").append(new SimpleDateFormat("yyyy-MM-dd").format(date)).append("\r\n");
}
}
if (vcattrs == null || vcattrs.contains("ADR")) {
encodeAddress(sb, "home,postal,parcel", ContactConstants.A_homeStreet, ContactConstants.A_homeCity, ContactConstants.A_homeState, ContactConstants.A_homePostalCode, ContactConstants.A_homeCountry, 2, fields);
encodeAddress(sb, "work,postal,parcel", ContactConstants.A_workStreet, ContactConstants.A_workCity, ContactConstants.A_workState, ContactConstants.A_workPostalCode, ContactConstants.A_workCountry, 2, fields);
encodeAddress(sb, "postal,parcel", ContactConstants.A_otherStreet, ContactConstants.A_otherCity, ContactConstants.A_otherState, ContactConstants.A_otherPostalCode, ContactConstants.A_otherCountry, 2, fields);
}
if (vcattrs == null || vcattrs.contains("TEL")) {
// omitting callback phone for now
encodePhone(sb, "car,voice", ContactConstants.A_carPhone, 2, fields);
encodePhone(sb, "home,fax", ContactConstants.A_homeFax, 2, fields);
encodePhone(sb, "home,voice", ContactConstants.A_homePhone, 2, fields);
encodePhone(sb, "cell,voice", ContactConstants.A_mobilePhone, 2, fields);
encodePhone(sb, "fax", ContactConstants.A_otherFax, 2, fields);
encodePhone(sb, "voice", ContactConstants.A_otherPhone, 2, fields);
encodePhone(sb, "pager", ContactConstants.A_pager, 2, fields);
encodePhone(sb, "work,fax", ContactConstants.A_workFax, 2, fields);
encodePhone(sb, "work,voice", ContactConstants.A_workPhone, 2, fields);
}
if (vcattrs == null || vcattrs.contains("EMAIL")) {
encodeField(sb, "EMAIL;TYPE=internet", ContactConstants.A_email, false, 2, fields);
encodeField(sb, "EMAIL;TYPE=internet", "workEmail", true, 1, fields);
}
if (vcattrs == null || vcattrs.contains("URL")) {
encodeField(sb, "URL;TYPE=home", ContactConstants.A_homeURL, false, 2, fields);
encodeField(sb, "URL", ContactConstants.A_otherURL, false, 2, fields);
encodeField(sb, "URL;TYPE=work", ContactConstants.A_workURL, false, 2, fields);
}
if (vcattrs == null || vcattrs.contains("ORG")) {
String org = fields.get(ContactConstants.A_company);
if (org != null && !org.trim().equals("")) {
org = vcfEncode(org);
String dept = fields.get(ContactConstants.A_department);
if (dept != null && !dept.trim().equals("")) {
org += ';' + vcfEncode(dept);
}
sb.append("ORG:").append(org).append("\r\n");
}
}
if (vcattrs == null || vcattrs.contains("TITLE"))
encodeField(sb, "TITLE", fields.get(ContactConstants.A_jobTitle));
if (vcattrs == null || vcattrs.contains("NOTE"))
encodeField(sb, "NOTE", fields.get(ContactConstants.A_notes));
if ((vcattrs == null || vcattrs.contains("PHOTO")) && attachments != null) {
for (Attachment attach : attachments) {
try {
if (attach.getName().equalsIgnoreCase(ContactConstants.A_image)) {
String field = "PHOTO;ENCODING=B";
if (attach.getContentType().startsWith("image/")) {
// We want just the subtype, ignoring any name etc
try {
ContentType ct = new ContentType(attach.getContentType());
if (ct != null) {
String subType = ct.getSubType();
if (!Strings.isNullOrEmpty(subType)) {
field += ";TYPE=" + ct.getSubType().toUpperCase();
}
}
} catch (ParseException e) {
}
}
String encoded = new String(Base64.encodeBase64Chunked(attach.getContent())).trim().replace("\r\n", "\r\n ");
sb.append(field).append(":\r\n ").append(encoded).append("\r\n");
}
} catch (OutOfMemoryError e) {
Zimbra.halt("out of memory", e);
} catch (Throwable t) {
ZimbraLog.misc.info("error fetching attachment content: " + attach.getName(), t);
}
}
}
if (vcattrs == null || vcattrs.contains("KEY")) {
String smimeCert = fields.get(ContactConstants.A_userSMIMECertificate);
if (smimeCert == null) {
smimeCert = fields.get(ContactConstants.A_userCertificate);
}
if (smimeCert != null) {
smimeCert = smimeCert.trim().replace("\r\n", "\r\n ");
String field = "KEY;ENCODING=B";
sb.append(field).append(":\r\n ").append(smimeCert).append("\r\n");
}
}
if (vcattrs == null || vcattrs.contains("CATEGORIES")) {
String[] tags = con.getTags();
if (tags.length > 0) {
StringBuilder sbtags = new StringBuilder();
for (String tagName : tags) {
sbtags.append(sbtags.length() == 0 ? "" : ",").append(vcfEncode(tagName));
}
sb.append("CATEGORIES:").append(sbtags).append("\r\n");
}
}
String uid = getUid(con);
if (vcattrs == null || vcattrs.contains("REV")) {
sb.append("REV:").append(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(new Date(con.getDate()))).append("\r\n");
}
if (vcattrs == null || vcattrs.contains("UID")) {
sb.append("UID:").append(uid).append("\r\n");
}
// sb.append("MAILER:Zimbra ").append(BuildInfo.VERSION).append("\r\n");
if ((vcattrs == null && includeZimbraXProps) || (vcattrs != null && vcattrs.contains("X-ZIMBRA-IMADDRESS"))) {
encodeField(sb, "X-ZIMBRA-IMADDRESS", "imAddress", true, 1, fields);
}
if ((vcattrs == null && includeZimbraXProps) || (vcattrs != null && vcattrs.contains("X-ZIMBRA-ANNIVERSARY"))) {
encodeField(sb, "X-ZIMBRA-ANNIVERSARY", ContactConstants.A_anniversary, false, 2, fields);
}
if ((vcattrs == null && includeZimbraXProps) || (vcattrs != null && vcattrs.contains("X-ZIMBRA-MAIDENNAME"))) {
String maidenName = con.get(ContactConstants.A_maidenName);
if (maidenName != null)
sb.append("X-ZIMBRA-MAIDENNAME:").append(maidenName).append("\r\n");
}
if (includeXProps) {
ListMultimap<String, VCardParamsAndValue> unknownVCardProps = con.getUnknownVCardProps();
for (String key : unknownVCardProps.keySet()) {
for (VCardParamsAndValue paramsAndValue : unknownVCardProps.get(key)) {
StringWriter sw = new StringWriter();
try (FoldingWriter writer = new FoldingWriter(sw)) {
writer.write(key);
String value = paramsAndValue.getValue();
Set<String> params = paramsAndValue.getParams();
if (!params.isEmpty()) {
writer.write(";");
writer.write(Joiner.on(";").join(params));
}
String vcfEncodedValue;
if (params.contains("ENCODING=B")) {
// should be raw BASE64
vcfEncodedValue = value;
} else {
vcfEncodedValue = vcfEncode(value);
}
writer.write(":");
writer.write(vcfEncodedValue);
writer.write("\r\n");
sb.append(sw.toString());
} catch (IOException e) {
ZimbraLog.misc.debug("Problem with adding property '%s' to VCARD - ignoring", key, e);
}
}
}
}
sb.append("END:VCARD\r\n");
return new VCard(fn, sb.toString(), fields, attachments, uid);
}
use of com.zimbra.cs.mailbox.Contact.Attachment in project zm-mailbox by Zimbra.
the class CreateContact method parseContact.
/*
* for CreateContact and ModifyContact replace mode
*/
static Pair<Map<String, Object>, List<Attachment>> parseContact(Element cn, ZimbraSoapContext zsc, OperationContext octxt, Contact existing) throws ServiceException {
Map<String, Object> fields = new HashMap<String, Object>();
List<Attachment> attachments = new ArrayList<Attachment>();
boolean isContactGroup = false;
Mailbox mbox = getRequestedMailbox(zsc);
for (Element elt : cn.listElements(MailConstants.E_ATTRIBUTE)) {
String name = elt.getAttribute(MailConstants.A_ATTRIBUTE_NAME);
if (name.trim().equals("")) {
throw ServiceException.INVALID_REQUEST("at least one contact field name is blank", null);
}
// do not allow specifying groupMember as attribute directly
disallowGroupMemberAttr(name);
Attachment attach = parseAttachment(elt, name, zsc, octxt, existing);
if (attach == null) {
disallowOperation(elt);
String value = elt.getText();
StringUtil.addToMultiMap(fields, name, value);
if (ContactConstants.A_type.equals(name) && ContactConstants.TYPE_GROUP.equals(value)) {
isContactGroup = true;
}
} else {
attachments.add(attach);
}
}
// parse contact group members
ContactGroup contactGroup = null;
for (Element elt : cn.listElements(MailConstants.E_CONTACT_GROUP_MEMBER)) {
if (!isContactGroup) {
// do not check existing contact, because this is replace mode or creating
throw ServiceException.INVALID_REQUEST(MailConstants.E_CONTACT_GROUP_MEMBER + " is only allowed for contact group", null);
}
disallowOperation(elt);
if (contactGroup == null) {
contactGroup = ContactGroup.init(existing, true);
if (existing != null) {
contactGroup.removeAllMembers();
}
}
String memberType = elt.getAttribute(MailConstants.A_CONTACT_GROUP_MEMBER_TYPE);
String memberValue = elt.getAttribute(MailConstants.A_CONTACT_GROUP_MEMBER_VALUE);
Member.Type type = Member.Type.fromSoap(memberType);
// bug 98526: remove account ID from item ID when it references the local account
String contactId = memberValue;
if (type == Member.Type.CONTACT_REF) {
ItemId iid = new ItemId(memberValue, mbox.getAccountId());
if (iid.getAccountId().equals(mbox.getAccountId())) {
contactId = String.valueOf(iid.getId());
}
}
contactGroup.addMember(type, contactId);
}
if (contactGroup != null) {
fields.put(ContactConstants.A_groupMember, contactGroup);
}
return new Pair<Map<String, Object>, List<Attachment>>(fields, attachments);
}
use of com.zimbra.cs.mailbox.Contact.Attachment in project zm-mailbox by Zimbra.
the class CreateContact method parseContactMergeMode.
static ParsedContact parseContactMergeMode(Element cn, ZimbraSoapContext zsc, OperationContext octxt, Contact existing) throws ServiceException {
Mailbox mbox = getRequestedMailbox(zsc);
ParsedContact.FieldDeltaList deltaList = new ParsedContact.FieldDeltaList();
List<Attachment> attachments = new ArrayList<Attachment>();
boolean isContactGroup = false;
for (Element elt : cn.listElements(MailConstants.E_ATTRIBUTE)) {
String name = elt.getAttribute(MailConstants.A_ATTRIBUTE_NAME);
if (name.trim().equals(""))
throw ServiceException.INVALID_REQUEST("at least one contact field name is blank", null);
Attachment attach = parseAttachment(elt, name, zsc, octxt, existing);
if (attach == null) {
String opStr = elt.getAttribute(MailConstants.A_OPERATION, null);
ParsedContact.FieldDelta.Op op = FieldDelta.Op.fromString(opStr);
String value = elt.getText();
deltaList.addAttrDelta(name, value, op);
if (ContactConstants.A_type.equals(name) && ContactConstants.TYPE_GROUP.equals(value) && ParsedContact.FieldDelta.Op.REMOVE != op) {
isContactGroup = true;
}
} else {
attachments.add(attach);
}
}
boolean discardExistingMembers = false;
for (Element elt : cn.listElements(MailConstants.E_CONTACT_GROUP_MEMBER)) {
if (!isContactGroup && !existing.isGroup()) {
throw ServiceException.INVALID_REQUEST(MailConstants.E_CONTACT_GROUP_MEMBER + " is only allowed for contact group", null);
}
String opStr = elt.getAttribute(MailConstants.A_OPERATION);
ModifyGroupMemberOperation groupMemberOp = ModifyGroupMemberOperation.fromString(opStr);
if (ModifyGroupMemberOperation.RESET.equals(groupMemberOp)) {
discardExistingMembers = true;
} else {
ParsedContact.FieldDelta.Op op = FieldDelta.Op.fromString(opStr);
ContactGroup.Member.Type memberType = ContactGroup.Member.Type.fromSoap(elt.getAttribute(MailConstants.A_CONTACT_GROUP_MEMBER_TYPE, null));
String memberValue = elt.getAttribute(MailConstants.A_CONTACT_GROUP_MEMBER_VALUE, null);
if (memberType == null) {
throw ServiceException.INVALID_REQUEST("missing member type", null);
}
if (StringUtil.isNullOrEmpty(memberValue)) {
throw ServiceException.INVALID_REQUEST("missing member value", null);
}
// bug 98526: remove account ID from item ID when it references the local account
String contactId = memberValue;
if (memberType == ContactGroup.Member.Type.CONTACT_REF) {
ItemId iid = new ItemId(memberValue, mbox.getAccountId());
if (!iid.getAccountId().equals(mbox.getAccountId())) {
contactId = memberValue;
} else {
contactId = String.valueOf(iid.getId());
}
}
deltaList.addGroupMemberDelta(memberType, contactId, op);
}
}
return new ParsedContact(existing).modify(deltaList, attachments, discardExistingMembers);
}
use of com.zimbra.cs.mailbox.Contact.Attachment in project zm-mailbox by Zimbra.
the class CreateContact method parseAttachment.
private static Attachment parseAttachment(Element elt, String name, ZimbraSoapContext zsc, OperationContext octxt, Contact existing) throws ServiceException {
// check for uploaded attachment
String attachId = elt.getAttribute(MailConstants.A_ATTACHMENT_ID, null);
if (attachId != null) {
if (Contact.isSMIMECertField(name)) {
elt.setText(parseCertificate(elt, name, zsc, octxt, existing));
return null;
} else {
Upload up = FileUploadServlet.fetchUpload(zsc.getAuthtokenAccountId(), attachId, zsc.getAuthToken());
UploadDataSource uds = new UploadDataSource(up);
return new Attachment(new DataHandler(uds), name, (int) up.getSize());
}
}
int itemId = (int) elt.getAttributeLong(MailConstants.A_ID, -1);
String part = elt.getAttribute(MailConstants.A_PART, null);
if (itemId != -1 || (part != null && existing != null)) {
MailItem item = itemId == -1 ? existing : getRequestedMailbox(zsc).getItemById(octxt, itemId, MailItem.Type.UNKNOWN);
try {
if (item instanceof Contact) {
Contact contact = (Contact) item;
if (part != null && !part.equals("")) {
try {
int partNum = Integer.parseInt(part) - 1;
if (partNum >= 0 && partNum < contact.getAttachments().size()) {
Attachment att = contact.getAttachments().get(partNum);
return new Attachment(att.getDataHandler(), name, att.getSize());
}
} catch (NumberFormatException nfe) {
}
throw ServiceException.INVALID_REQUEST("invalid contact part number: " + part, null);
} else {
VCard vcf = VCard.formatContact(contact);
return new Attachment(vcf.getFormatted().getBytes("utf-8"), "text/x-vcard; charset=utf-8", name, vcf.fn + ".vcf");
}
} else if (item instanceof Message) {
Message msg = (Message) item;
if (part != null && !part.equals("")) {
try {
MimePart mp = Mime.getMimePart(msg.getMimeMessage(), part);
if (mp == null) {
throw MailServiceException.NO_SUCH_PART(part);
}
DataSource ds = new MimePartDataSource(mp);
return new Attachment(new DataHandler(ds), name);
} catch (MessagingException me) {
throw ServiceException.FAILURE("error parsing blob", me);
}
} else {
DataSource ds = new MessageDataSource(msg);
return new Attachment(new DataHandler(ds), name, (int) msg.getSize());
}
} else if (item instanceof Document) {
Document doc = (Document) item;
if (part != null && !part.equals("")) {
throw MailServiceException.NO_SUCH_PART(part);
}
DataSource ds = new DocumentDataSource(doc);
return new Attachment(new DataHandler(ds), name, (int) doc.getSize());
}
} catch (IOException ioe) {
throw ServiceException.FAILURE("error attaching existing item data", ioe);
} catch (MessagingException e) {
throw ServiceException.FAILURE("error attaching existing item data", e);
}
}
return null;
}
Aggregations