bool SmtpClient::sendMessage(Connection* c, Mail* mail) { bool rval = true; // send headers Message msg = mail->getMessage(); DynamicObjectIterator i = msg["headers"].getIterator(); while(rval && i->hasNext()) { // iterate over each header DynamicObjectIterator hi = i->next().getIterator(); bool comma = false; while(rval && hi->hasNext()) { DynamicObject header = hi->next(); if(rval && !comma) { // send header name and colon rval = c->getOutputStream()->write( i->getName(), strlen(i->getName())) && c->getOutputStream()->write(": ", 2); } if(rval && comma) { // send comma rval = c->getOutputStream()->write(", ", 2); } else { comma = true; } if(rval) { // send smtp-encoded header value string value = header->getString(); Mail::smtpMessageEncode(value); rval = c->getOutputStream()->write(value.c_str(), value.length()); } } // send CRLF if(rval) { rval = sendCrlf(c); } } if(rval) { // send encoded body string body = mail->getTransferEncodedBody(); rval = c->getOutputStream()->write(body.c_str(), body.length()); } return rval; }
/** * Recursively applies context to the given input object. * * @param ctx the context to use. * @param usedCtx the used context values. * @param predicate the related predicate or NULL if none. * @param in the input object. * @param out the contextualized output object. */ static void _applyContext( DynamicObject& ctx, DynamicObject& usedCtx, const char* predicate, DynamicObject& in, DynamicObject& out) { if(in.isNull()) { out.setNull(); } else { // initialize output DynamicObjectType inType = in->getType(); out->setType(inType); if(inType == Map) { // add context to each property in the map char* tmp = NULL; DynamicObjectIterator i = in.getIterator(); while(i->hasNext()) { // compact predicate DynamicObject& next = i->next(); DynamicObject cp(NULL); const char* p; if(strcmp(i->getName(), "@") == 0) { p = "@"; } else { cp = _compactString(ctx, usedCtx, NULL, i->getName(), &tmp); p = cp; } // recurse _applyContext(ctx, usedCtx, p, next, out[p]); } free(tmp); } else if(inType == Array) { // apply context to each object in the array DynamicObjectIterator i = in.getIterator(); while(i->hasNext()) { DynamicObject& next = i->next(); _applyContext(ctx, usedCtx, predicate, next, out->append()); } } // only strings need context applied, numbers & booleans don't else if(inType == String) { // compact string char* tmp = NULL; out = _compactString(ctx, usedCtx, predicate, in->getString(), &tmp); free(tmp); } } }
static bool _setDecodedParam( Statement* s, unsigned int index, DynamicObject& param, DynamicObject& value) { bool rval = true; if(param->hasMember("encode")) { // FIXME: could use streams here and handle types other than string, // but the DatabaseClient API might be abandoned before this actually // ever really gets used to that extent // fill byte buffer with initial data ByteBuffer b; b.put(value->getString(), value->length(), true); // apply each decoding // FIXME: optimize this by doing it once and storing it when // defining the schema DynamicObject decode = param["encode"].clone(); decode->reverse(); DynamicObjectIterator i = decode.getIterator(); while(rval && i->hasNext()) { const char* type = i->next()->getString(); // convert hex to binary if(strcmp(type, "hex") == 0) { const char* hex = b.bytes(); unsigned int len = b.length(); unsigned int binLen = (len >> 1) + 1; char bin[binLen]; rval = Convert::hexToBytes(hex, len, bin, binLen); if(rval) { b.clear(); b.put(bin, binLen, true); } } } // only blobs are supported at the moment rval = rval && s->setBlob(index, b.bytes(), b.length()); }
// a helper function that converts message parameters into a dom element static void paramsToElement(SoapMessage& msg, DynamicObject& params, Element& e) { if(params->getType() == Map) { DynamicObjectIterator pi = params.getIterator(); while(pi->hasNext()) { DynamicObject& p = pi->next(); // add param element Element param; param["name"] = pi->getName(); param["namespace"] = msg["namespace"]->getString(); e["children"][pi->getName()]->append(param); paramsToElement(msg, p, param); } } else { // use 0/1 for booleans e["data"] = (params->getType() == Boolean) ? (params->getBoolean() ? "1" : "0") : params->getString(); } }
/** * Normalizes a value using the given context. * * @param ctx the context. * @param value the value to normalize. * @param type the expected RDF type, use RDF_TYPE_UNKNOWN if not known. * @param predicate an optional predicate for the value (used to look up * type coercion info). * @param usedCtx a context to update if a value was used from "ctx". * * @return the normalized string. */ static string _normalizeValue( DynamicObject& ctx, DynamicObject value, RdfType type, const char* predicate, DynamicObject* usedCtx) { string rval; // "@" or "a"/RDF_TYPE predicates have values that are IRIs or CURIEs if(predicate != NULL && (strcmp(predicate, "@") == 0 || strcmp(predicate, "a") == 0 || strcmp(predicate, RDF_TYPE_NORM) == 0)) { type = RDF_TYPE_IRI; } // IRI "@" is already normalized if(type == RDF_TYPE_IRI && strcmp(value, "@") == 0) { rval.assign(value); } // IRI "a" is special rdf type else if(type == RDF_TYPE_IRI && strcmp(value, "a") == 0) { rval.assign(RDF_TYPE_NORM); } else { string datatype; // look for type coercion info if(type == RDF_TYPE_UNKNOWN && predicate != NULL && !ctx.isNull() && ctx->hasMember("#types") && ctx["#types"]->hasMember(predicate)) { DynamicObject& tci = ctx["#types"][predicate]; if(usedCtx != NULL) { (*usedCtx)["#types"][predicate] = tci.clone(); } // handle specific type if(tci->getType() == String) { rval = value->getString(); datatype = _normalizeValue(ctx, tci, RDF_TYPE_IRI, NULL, usedCtx); type = (strcmp(datatype.c_str(), XSD_ANY_URI_NORM) == 0) ? RDF_TYPE_IRI : RDF_TYPE_TYPED_LITERAL; } // handle type preferences in order else { DynamicObjectIterator ti = tci.getIterator(); while(type == RDF_TYPE_UNKNOWN && ti->hasNext()) { // FIXME: if value works w/type, set value, datatype, type //type = RDF_TYPE_TYPED_LITERAL; } } } // determine type from DynamicObjectType else if(type == RDF_TYPE_UNKNOWN && value->getType() != String) { type = RDF_TYPE_TYPED_LITERAL; rval = value->getString(); // handle native xsd types if(value->isNumber()) { datatype = value->isInteger() ? XSD_INTEGER : XSD_DOUBLE; } else if(value->getType() == Boolean) { datatype = XSD_BOOLEAN; } else { // FIXME: this should never happen? datatype = XSD_ANY_TYPE; } } else { // JSON-LD decode RdfType t = type; _decode(value, type, rval, datatype); if(type == RDF_TYPE_TYPED_LITERAL) { _expandCurie(ctx, datatype.c_str(), datatype, usedCtx); } // preserve expected type if(t != RDF_TYPE_UNKNOWN) { type = t; } } // expand CURIE if(type == RDF_TYPE_IRI) { _expandCurie(ctx, rval.c_str(), rval, usedCtx); } // JSON-LD encode rval = _encode(type, rval.c_str(), datatype.c_str()); } return rval; }
bool JsonWriter::write(DynamicObject& dyno, OutputStream* os, int level) { bool rval = true; if(level < 0) { level = mIndentLevel; } if(dyno.isNull()) { rval = os->write("null", 4); } else { switch(dyno->getType()) { case String: { const char* temp = dyno->getString(); size_t length = strlen(temp); // Note: UTF-8 has a maximum of 6-bytes per character when // encoded in json format ("\u1234") string encoded; encoded.reserve(length); encoded.push_back('"'); char unicode[6]; for(size_t i = 0; i < length; ++i) { unsigned char c = temp[i]; if((c >= 0x5d /* && c <= 0x10FFFF */) || (c >= 0x23 && c <= 0x5B) || (c == 0x21) || (c == 0x20)) { // TODO: check this handles UTF-* properly encoded.push_back(c); } else { encoded.push_back('\\'); switch(c) { case '"': /* 0x22 */ case '\\': /* 0x5C */ // '/' is in the RFC but not required to be escaped //case '/': /* 0x2F */ encoded.push_back(c); break; case '\b': /* 0x08 */ encoded.push_back('b'); break; case '\f': /* 0x0C */ encoded.push_back('f'); break; case '\n': /* 0x0A */ encoded.push_back('n'); break; case '\r': /* 0x0D */ encoded.push_back('r'); break; case '\t': /* 0x09 */ encoded.push_back('t'); break; default: // produces "u01af" (4 digits of 0-filled hex) snprintf(unicode, 6, "u%04x", c); encoded.append(unicode, 5); break; } } } // end string serialization and write encoded string encoded.push_back('"'); rval = os->write(encoded.c_str(), encoded.length()); break; } case Boolean: case Int32: case UInt32: case Int64: case UInt64: case Double: { const char* temp = dyno->getString(); rval = os->write(temp, strlen(temp)); break; } case Map: { // start map serialization rval = (mCompact || dyno->length() == 0) ? os->write("{", 1) : os->write("{\n", 2); // serialize each map member DynamicObjectIterator i = dyno.getIterator(); while(rval && i->hasNext()) { DynamicObject& next = i->next(); // serialize indentation and start serializing member name if((rval = writeIndentation(os, level + 1) && os->write("\"", 1) && os->write(i->getName(), strlen(i->getName())))) { // end serializing member name, serialize member value rval = ((mCompact) ? os->write("\":", 2) : os->write("\": ", 3)) && write(next, os, level + 1); // serialize delimiter if appropriate if(rval && i->hasNext()) { rval = os->write(",", 1); } // add formatting if appropriate if(rval && !mCompact) { rval = os->write("\n", 1); } } } // end map serialization if(dyno->length() > 0) { rval = rval && writeIndentation(os, level); } rval = rval && os->write("}", 1); break; } case Array: { // start array serialization rval = (mCompact || dyno->length() == 0) ? os->write("[", 1) : os->write("[\n", 2); // serialize each array element DynamicObjectIterator i = dyno.getIterator(); while(rval && i->hasNext()) { // serialize indentation and array value rval = writeIndentation(os, level + 1) && write(i->next(), os, level + 1); // serialize delimiter if appropriate if(rval && i->hasNext()) { rval = os->write(",", 1); } // add formatting if appropriate if(rval && !mCompact) { rval = os->write("\n", 1); } } // end array serialization if(dyno->length() > 0) { rval = rval && writeIndentation(os, level); } rval = rval && os->write("]", 1); break; } } } return rval; }
bool Int::isValid( DynamicObject& obj, ValidatorContext* context) { bool rval; DynamicObjectType objType; rval = !obj.isNull(); if(rval) { objType = obj->getType(); if(objType == String) { objType = DynamicObject::determineType(obj->getString()); } // type check rval = objType == Int32 || objType == UInt32 || objType == Int64 || objType == UInt64; } if(!rval) { DynamicObject detail = context->addError("monarch.validation.ValueError", &obj); detail["validator"] = "monarch.validator.Int"; detail["message"] = mErrorMessage ? mErrorMessage : "The given value type is required to be an integer."; } // absolute value of dyno value uint64_t val = 0; // flag if val is negative bool valneg = false; // get value for min/max check if(rval) { // get value and sign switch(objType) { case Int32: case Int64: { int64_t raw = obj->getInt64(); valneg = (raw < 0); val = (uint64_t)(valneg ? -raw : raw); break; } case UInt32: case UInt64: { valneg = false; val = obj->getUInt64(); break; } default: // never get here break; } } // min check if(rval) { if(mMinNegative != valneg) { // signs are different // val meets the minimum unless val is negative rval = !valneg; } else { // signs are the same // val meets the minimum if: // 1. val is positive and larger than mMin // 2. val is negative and smaller than mMin rval = (!valneg ? val >= mMin : val <= mMin); } // set exception on failure if(!rval) { DynamicObject detail = context->addError("monarch.validation.ValueError", &obj); detail["validator"] = "monarch.validator.Int"; detail["message"] = mErrorMessage ? mErrorMessage : "The given integer value is less than the required minimum " "integer value."; detail["expectedMin"] = mMin; } } // max check if(rval) { if(mMaxNegative != valneg) { // signs are different // val meets the maximum unless val is positive rval = valneg; } else { // signs are the same // val meets the maximum if: // 1. val is positive and smaller than mMax // 2. val is negative and larger than mMax rval = (valneg ? val >= mMax : val <= mMax); } // set exception on failure if(!rval) { DynamicObject detail = context->addError("monarch.validation.ValueError", &obj); detail["validator"] = "monarch.validator.Int"; detail["message"] = mErrorMessage ? mErrorMessage : "The given integer value is greater than the allowable maximum " "integer value."; detail["expectedMax"] = mMax; } } if(rval) { context->addSuccess(); } return rval; }
bool ControlPoint::getServiceDescription(Service& service) { bool rval = false; // get the description url for the service Url url; url.format("%s%s", service["rootURL"]->getString(), service["SCPDURL"]->getString()); // get description string description; rval = getDescription(&url, description); if(rval) { // parse result Element root; DomReader reader; ByteArrayInputStream bais(description.c_str(), description.length()); reader.start(root); if((rval = reader.read(&bais) && reader.finish())) { MO_CAT_DEBUG(MO_UPNP_CAT, "Parsing service from xml: %s", JsonWriter::writeToString(root).c_str()); // parse out actions service["actions"]->setType(Map); if(root["children"]->hasMember("actionList")) { Element& actionList = root["children"]["actionList"][0]; if(actionList["children"]->hasMember("action")) { DynamicObjectIterator ai = actionList["children"]["action"].getIterator(); while(ai->hasNext()) { DynamicObject& action = ai->next(); // get action basics Action a; a["name"] = action["children"]["name"][0]["data"]->getString(); a["arguments"]->setType(Map); a["arguments"]["in"]->setType(Array); a["arguments"]["out"]->setType(Array); // add action arguments if(action["children"]->hasMember("argumentList")) { Element& argList = action["children"]["argumentList"][0]; DynamicObjectIterator argi = argList["children"]["argument"].getIterator(); while(argi->hasNext()) { DynamicObject& argument = argi->next(); // build argument DynamicObject name; name = argument["children"]["name"] [0]["data"]->getString(); const char* direction = argument["children"]["direction"] [0]["data"]->getString(); if(strcmp(direction, "in") == 0) { a["arguments"]["in"]->append(name); } else { a["arguments"]["out"]->append(name); } if(argument["children"]->hasMember("retval")) { a["retval"][name->getString()] = argument["children"]["retval"] [0]["data"]->getString(); } } // add action to service service["actions"][a["name"]->getString()] = a; } } } } } } if(rval) { MO_CAT_DEBUG(MO_UPNP_CAT, "Parsed service: %s", JsonWriter::writeToString(service).c_str()); } return rval; }