MEDIUM: sample: add fiftyone_degrees converter.

It takes up to 5 string arguments that are to be 51Degrees property names.
It will then create a chunk with values detected based on the request header
supplied (this should be the User-Agent).
diff --git a/src/sample.c b/src/sample.c
index 47d48c8..6418be8 100644
--- a/src/sample.c
+++ b/src/sample.c
@@ -32,6 +32,10 @@
 #include <proto/sample.h>
 #include <proto/stick_table.h>
 
+#ifdef USE_51DEGREES
+#include <51Degrees.h>
+#endif
+
 /* sample type names */
 const char *smp_to_type[SMP_TYPES] = {
 	[SMP_T_BOOL] = "bool",
@@ -2124,6 +2128,69 @@
 	smp->type = SMP_T_BOOL;
 	return 1;
 }
+
+#ifdef USE_51DEGREES
+static int fiftyone_degrees(const struct arg *args,
+                           struct sample *smp, void *private)
+{
+	int i, j, found; // used in loops.
+	fiftyoneDegreesWorkset* ws; // workset for detection.
+	char no_data[] = "NoData"; // response when no data could be found.
+	struct _51d_property_names *property;
+	struct chunk *tmp;
+
+	// use a temporary trash buffer and copy data in it
+	smp->data.str.str[smp->data.str.len] = '\0';
+
+	// create workset. this will later contain detection results.
+	ws = fiftyoneDegreesCreateWorkset(&global._51d_data_set);
+	if (!ws)
+		return 0;
+
+	// perform detection.
+	fiftyoneDegreesMatch(ws, smp->data.str.str);
+
+	i = 0;
+	tmp = get_trash_chunk();
+	chunk_reset(tmp);
+	// loop through property names passed to the filter and fetch them from the dataset.
+	while (args[i].data.str.str) {
+		found = j = 0;
+		// try to find request property in dataset.
+		list_for_each_entry(property, &global._51d_property_names, list) {
+			if (strcmp(property->name, args[i].data.str.str) == 0) {
+				found = 1;
+				fiftyoneDegreesSetValues(ws, j);
+				chunk_appendf(tmp, "%s", fiftyoneDegreesGetValueName(ws->dataSet, *ws->values));
+				break;
+			}
+			++j;
+		}
+		if (!found)
+			chunk_appendf(tmp, "%s", no_data);
+
+		// add seperator
+		if (global._51d_property_seperator)
+			chunk_appendf(tmp, "%c", global._51d_property_seperator);
+		else
+			chunk_appendf(tmp, ",");
+		++i;
+	}
+
+	if (tmp->len) {
+		--tmp->len;
+		tmp->str[tmp->len] = '\0';
+	}
+
+	smp->data.str.str = tmp->str;
+	smp->data.str.len = strlen(smp->data.str.str);
+
+	fiftyoneDegreesFreeWorkset(ws);
+
+	return 1;
+}
+#endif
+
 
 /************************************************************************/
 /*       All supported sample fetch functions must be declared here     */
@@ -2278,6 +2345,9 @@
 	{ "div",    sample_conv_arith_div,  ARG1(1,UINT), NULL, SMP_T_UINT, SMP_T_UINT },
 	{ "mod",    sample_conv_arith_mod,  ARG1(1,UINT), NULL, SMP_T_UINT, SMP_T_UINT },
 	{ "neg",    sample_conv_arith_neg,             0, NULL, SMP_T_UINT, SMP_T_UINT },
+#ifdef USE_51DEGREES
+	{ "51d",    fiftyone_degrees,       ARG5(1,STR,STR,STR,STR,STR), NULL, SMP_T_STR, SMP_T_STR },
+#endif
 
 	{ NULL, NULL, 0, 0, 0 },
 }};