Skip to content

Commit 688bf33

Browse files
committed
Unfold vCard before using it.
Follow the RFC by unfolding folded vCard lines (CRLF WSP) before using the vCard. This is done in place as we will be accessing all the data immediately anyway as we pass the automata over it so it is likely to stay in cache. This pipelined approach seems easier than special handling of continuation lines and follows the spirit of the specification.
1 parent 88de279 commit 688bf33

File tree

3 files changed

+55
-4
lines changed

3 files changed

+55
-4
lines changed

src/vcard.c

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,51 @@ xregcomp(regex_t *preg, const char *regex, int cflags) {
7171
return 0;
7272
}
7373

74+
/**
75+
* Unfold a vCard per RFC6350 section 3.2.
76+
*
77+
* It will remove the gaps between folded lines in-place.
78+
*
79+
* \parm[in,out] card The vcard.
80+
*
81+
* \retval 0 If there were no errors.
82+
* \retval 1 If an error was encounted.
83+
**/
84+
static int
85+
unfold(char *vcard)
86+
{
87+
static const char r[] = "\r\n[ \t]"; /* Continuation fold */
88+
regmatch_t matches[1];
89+
regex_t re;
90+
size_t length = strlen(vcard);
91+
size_t in_ptr = 0; /* AKA cut_to */
92+
size_t out_ptr = 0; /* AKA cut_from */
93+
94+
if (xregcomp(&re, r, 0) != 0) {
95+
return 1;
96+
}
97+
98+
/* Hunt for folds and move the chunks inbetween them back by
99+
* the accumulated number of folding characters. */
100+
while (regexec(&re, vcard + in_ptr, 1, matches, 0) == 0) {
101+
if (matches[0].rm_so == -1 || matches[0].rm_so == -1) {
102+
errx(EXIT_FAILURE, _("inconsistent regex result"));
103+
}
104+
memmove(vcard + out_ptr,
105+
vcard + in_ptr,
106+
matches[0].rm_so);
107+
in_ptr = in_ptr + matches[0].rm_eo;
108+
out_ptr = out_ptr + matches[0].rm_so;
109+
}
110+
if (options.verbose) {
111+
fprintf(stderr, "Unfolding cut %zd bytes\n", in_ptr - out_ptr);
112+
}
113+
memmove(vcard + out_ptr, vcard + in_ptr, length - in_ptr + 1);
114+
115+
regfree(&re);
116+
return 0;
117+
}
118+
74119
/**
75120
* Search a query's result. This will run regexs over the result
76121
* to filter the data.
@@ -85,7 +130,7 @@ xregcomp(regex_t *preg, const char *regex, int cflags) {
85130
* \retval 1 If an error was encounted.
86131
**/
87132
int
88-
search(const char *card)
133+
search(char *card)
89134
{
90135
/* Regex patterns */
91136
static const char r[] = "%s(.*):(.*)"; /* Whole result */
@@ -107,6 +152,11 @@ search(const char *card)
107152

108153
regmatch_t match[3] = {0}; /* Regex matches */
109154

155+
if (unfold(card)) {
156+
warnx(_("Error unfolding vCard."));
157+
return(EXIT_FAILURE);
158+
}
159+
110160
/* Generate a quoted query term */
111161
if (quote(options.term, &qt)) {
112162
warnx(_("Unable to build quoted term."));

src/vcard.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ extern "C"
3232
{
3333
#endif
3434

35-
/** Search the vcard */
36-
int search(const char *);
35+
/** Search the vcard.
36+
* The supplied card string will be unfolded in place so must be modifiable. */
37+
int search(char *);
3738

3839
/** Quote a string for regex's */
3940
int quote(const char *, char **);

src/xml.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ walk_tree(xmlDocPtr doc, xmlNode *node)
107107
_("Data:\n%s\n"),
108108
data);
109109
}
110-
search((const char *)data);
110+
search((char *)data);
111111
xmlFree(data);
112112
}
113113
}

0 commit comments

Comments
 (0)