Exclude coverage for map-agent
[platform/core/connectivity/bluetooth-agent.git] / map-agent / map_bmessage.c
1 /*
2  * Bluetooth-agent
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:  Hocheol Seo <hocheol.seo@samsung.com>
7  *               Girishashok Joshi <girish.joshi@samsung.com>
8  *               Chanyeol Park <chanyeol.park@samsung.com>
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *              http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <glib.h>
27
28 #include <ITapiNetText.h>
29
30 #include <map_bmessage.h>
31 #include <bluetooth_map_agent.h>
32
33 #define CRLF_LEN 2
34 #define BT_SMS_DATA_MAX_LEN 165
35
36 #define BMSG_TAG "BEGIN:BMSG\r\n"
37 #define VER_TAG "VERSION:"
38 #define STATUS_TAG "STATUS:"
39 #define TYPE_TAG "TYPE:"
40 #define FOLDER_TAG "FOLDER:"
41 #define VCARD_BEGIN_TAG "BEGIN:VCARD\r\n"
42 #define VCARD_END_TAG "END:VCARD\r\n"
43 #define VCARD_N_TAG "N:"
44 #define VCARD_FN_TAG "FN:"
45 #define VCARD_TEL_TAG "TEL:"
46 #define VCARD_EMAIL_TAG "EMAIL:"
47 #define BENV_TAG "BEGIN:BENV\r\n"
48 #define BBODY_TAG "BEGIN:BBODY\r\n"
49 #define MSG_TAG "BEGIN:MSG\r\n"
50 #define PARTID_TAG "PARTID:"
51 #define ENCODING_TAG "ENCODING:"
52 #define CHARSET_TAG "CHARSET:"
53 #define LANGUAGE_TAG "LANGUAGE:"
54 #define LENGTH_TAG "LENGTH:"
55
56 static guint8 g_enc_lvl = 1;
57
58 /* LCOV_EXCL_START */
59 void print_bmsg(struct bmsg_data *bmsg)
60 {
61         FN_START;
62         if (bmsg == NULL)
63                 return;
64
65         struct benv_data *env_data = NULL;
66
67         DBG("bmsg->version = %s", bmsg->version);
68         DBG("bmsg->status = %s", bmsg->status);
69         DBG("bmsg->type = %s", bmsg->type);
70         DBG_SECURE("bmsg->folder = %s", bmsg->folder);
71
72         if (bmsg->originator_vcard_data) {
73                 DBG_SECURE("bmsg->originator_vcard_data->version = %s",
74                                                 bmsg->originator_vcard_data->version);
75                 DBG_SECURE("bmsg->originator_vcard_data->n = %s",
76                                                 bmsg->originator_vcard_data->n);
77         }
78
79         int i = 0;
80         env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i);
81         while (env_data != NULL) {
82
83                 DBG("env_data = %d", env_data->encapsulation_level);
84                 int k = 0;
85                 struct bmsg_vcard *rvcard;
86
87                 rvcard = g_slist_nth_data(env_data->recipient_vcard, k);
88
89                 while (rvcard != NULL) {
90                         k++;
91
92                         if (rvcard->version != NULL)
93                                 DBG("vcard->version = %s\n", rvcard->version);
94                         if (rvcard->n != NULL)
95                                 DBG_SECURE("vcard->n = %s\n", rvcard->n);
96                         if (rvcard->fn != NULL)
97                                 DBG_SECURE("vcard->fn = %s\n", rvcard->fn);
98                         if (rvcard->tel != NULL)
99                                 DBG_SECURE("vcard->tel = %s\n", rvcard->tel);
100                         if (rvcard->email != NULL)
101                                 DBG_SECURE("vcard->email = %s\n", rvcard->email);
102
103                         rvcard = g_slist_nth_data(env_data->recipient_vcard, k);
104                 }
105
106                 if (env_data->body_content != NULL) {
107                         DBG_SECURE("env_data->body_content->length = %"
108                                                 G_GUINT64_FORMAT "\n",
109                                                 env_data->body_content->length);
110                         DBG_SECURE("env_data->body_content->msg = %s\n",
111                                                 env_data->body_content->msg);
112                 }
113
114                 i++;
115
116                 if (i > 2)
117                         break;
118
119                 env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i);
120         }
121         FN_END;
122 }
123
124 static gchar *__bt_unpack_gsm7bit_msg(const char* pdu, int in_len)
125 {
126         FN_START;
127         int i;
128         int pos = 0;
129         int shift = 0;
130         gchar data[BT_SMS_DATA_MAX_LEN + 1] = {0,};
131
132         for (i = 0; i < in_len; i++) {
133                 if (shift == 0) {
134                         data[i] = pdu[pos] & 0x7F;
135
136                         shift = 7;
137                         pos++;
138                 } else {
139                         data[i] = (pdu[pos - 1] >> shift) |
140                                                 (pdu[pos] << (8 - shift));
141                         data[i] &= 0x7F;
142
143                         shift--;
144                         if (shift > 0)
145                                 pos++;
146                 }
147         }
148
149         DBG_SECURE("msg = %s\n", data);
150         FN_END;
151         return g_strdup(data);
152 }
153
154 static gchar *__bt_get_msg_body_from_pdu(gchar *pdu, guint64 pdu_len)
155 {
156         FN_START;
157         int index = 0;
158         int i;
159         int j = 0;
160         int dcs;
161         int udh = 0;
162         int coding_scheme;
163         int phone_num_len = 0;
164         char temp[3];
165         char msg_data[BT_SMS_DATA_MAX_LEN + 1] = {0,};
166         unsigned char pdu_data[TAPI_NETTEXT_MSG_SIZE_MAX] = {0,};
167
168         for (i = 0; i < (pdu_len - 1);) {
169                 snprintf(temp, sizeof(temp), "%c%c", pdu[i], pdu[i+1]);
170
171                 pdu_data[j] = g_ascii_strtoull(temp, NULL, 16);
172                 DBG("pdu_data = %02x\n", pdu_data[j]);
173                 j++;
174                 i = i + 2;
175         }
176
177         DBG("pdu[%d] = %x\n", index, pdu_data[index]);
178         if (pdu[index] == 0x00)
179                 index++;
180         else
181                 index = index + pdu_data[index];
182
183         /* TP-MTI */
184         index = index + 1;
185
186         if (pdu_data[index] & 0x40)
187                 udh = 1;
188
189         DBG("udh = %d", udh);
190
191         /* TP-MR */
192         index = index + 1;
193
194         /* phone number length */
195         index = index + 1;
196         DBG("pdu[%d] = %x\n", index, pdu_data[index]);
197
198         if ((pdu_data[index] % 2) == 0)
199                 phone_num_len = pdu_data[index] / 2;
200         else
201                 phone_num_len = pdu_data[index] / 2 + 1;
202
203         DBG("phone_num_len [%d]\n", phone_num_len);
204
205         /* phone number type */
206         index = index + 1;
207
208         /* phone_num_len/2 encoded phone num length */
209         index = index + phone_num_len;
210
211         /* TP-PID */
212         index = index + 1;
213
214         /* TP-DCS */
215         index = index + 1;
216
217         dcs = pdu_data[index];
218         coding_scheme = (dcs & 0x0C) >> 2;
219         DBG("coding_scheme = %d\n", coding_scheme);
220
221         /* TP-VP */
222         index = index + 1;
223
224         /* TP-UDL */
225         index = index + 1;
226         int udl = pdu_data[index];
227         DBG("udl = %x\n", udl);
228
229         /* message body */
230         index = index + 1;
231
232         memcpy(msg_data, (void*)&pdu_data[index], udl);
233
234         FN_END;
235         return __bt_unpack_gsm7bit_msg(msg_data, udl);
236 }
237
238 static gchar *__bt_get_valid_number(gchar* num)
239 {
240         FN_START;
241         int len;
242         int i = 0;
243         int j = 0;
244         gchar *valid_num;
245
246         if (!num)
247                 return NULL;
248
249         len = strlen(num);
250
251         valid_num = g_malloc0(len + 1);
252         retv_if(valid_num == NULL, NULL);
253
254         for (i = 0, j = 0; i < len; i++) {
255
256                 if (num[i] != '-') {
257                         valid_num[j] = num[i];
258                         j++;
259                 }
260         }
261
262         valid_num[j] = '\0';
263
264         FN_END;
265         return valid_num;
266 }
267
268 char *bmsg_get_msg_folder(struct bmsg_data *bmsg)
269 {
270         FN_START;
271         return g_strdup(bmsg->folder);
272 }
273
274 char *bmsg_get_msg_body(struct bmsg_data *bmsg, gboolean utf)
275 {
276         FN_START;
277         struct benv_data *env_data;
278         int i = 0;
279
280         env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i);
281
282         while (env_data != NULL) {
283                 if (env_data->body_content != NULL) {
284                         DBG_SECURE("env_data->body_content->msg = %s\n",
285                                                 env_data->body_content->msg);
286                         DBG_SECURE("env_data->body_content->length = %"
287                                                 G_GUINT64_FORMAT "\n",
288                                                 env_data->body_content->length);
289
290                         if (utf == FALSE) {
291                                 return __bt_get_msg_body_from_pdu(
292                                                 env_data->body_content->msg,
293                                                 env_data->body_content->length);
294                         } else {
295                                 return g_strndup(
296                                                 env_data->body_content->msg,
297                                                 env_data->body_content->length);
298                         }
299                 }
300
301                 i++;
302                 if (i > 2)
303                         break;
304
305                 env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i);
306         }
307
308         FN_END;
309         return NULL;
310 }
311
312 char *get_line(char *string, int *len)
313 {
314         int i = 0;
315         while (string[i] != '\n' && string[i] != '\0')
316                 i++;
317
318         *len = i;
319         return g_strndup(string, i - 1);
320 }
321
322 gboolean bmsg_parse_msg_body(const char *message,
323                         char **body, char **subject)
324 {
325         FN_START;
326         DBG("Message: %s", message);
327         char *temp = (char *)message;
328         char *line = NULL;
329         int len;
330
331         *subject = NULL;
332         *body = NULL;
333         while ((line = get_line(temp, &len)) != NULL) {
334                 if (!g_ascii_strncasecmp(line, "Date:", strlen("Date:"))) {
335                         //Currently nothing to be done
336                 } else if (!g_ascii_strncasecmp(line, "Subject:", strlen("Subject:"))) {
337                         char *sub = line + strlen("Subject:");
338                         while (*sub == ' ')
339                                 sub++;
340                         DBG("Subject: %s", sub);
341                         *subject = g_strdup(sub);
342                 } else if (!g_ascii_strncasecmp(line, "From:", strlen("From:"))) {
343                         //Currently nothing to be done
344                 } else if (!g_ascii_strncasecmp(line, "To:", strlen("To:"))) {
345                         //Currently nothing to be done
346                 } else {
347                         DBG("BODY: %s", temp);
348                         *body = g_strdup(temp);
349                         g_free(line);
350                         break;
351                 }
352
353                 while ((temp[len] == '\r' || temp[len] == '\n') && temp[len] != '\0')
354                         len++;
355
356                 temp = temp + len;
357
358                 g_free(line);
359         }
360         return TRUE;
361         FN_END;
362 }
363
364 GSList *bmsg_get_msg_recepients(struct bmsg_data *bmsg, int msg_type)
365 {
366         FN_START;
367         struct benv_data *env_data;
368         GSList *receiver = NULL;
369         int i = 0;
370
371         env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i);
372
373         while (env_data != NULL) {
374
375                 DBG("env_data = %d", env_data->encapsulation_level);
376                 int k = 0;
377                 struct bmsg_vcard *rvcard;
378
379                 rvcard = g_slist_nth_data(env_data->recipient_vcard, k);
380                 while (rvcard != NULL) {
381                         k++;
382
383                         if (msg_type == BT_MAP_ID_SMS) {
384                                 if (rvcard->tel != NULL) {
385                                         DBG_SECURE("vcard->tel = %s\n", rvcard->tel);
386                                         receiver = g_slist_append(receiver,
387                                                                         rvcard->tel);
388                                 }
389                         } else {
390                                 if (rvcard->email != NULL) {
391                                         DBG_SECURE("vcard->email = %s\n", rvcard->email);
392                                         receiver = g_slist_append(receiver,
393                                                                         rvcard->email);
394                                 }
395                         }
396                         rvcard = g_slist_nth_data(env_data->recipient_vcard, k);
397                 }
398
399                 i++;
400                 if (i > 2)
401                         break;
402
403                 env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i);
404         }
405         FN_END;
406         return receiver;
407 }
408
409 void bmsg_free_vcard_data(struct bmsg_vcard *vcard_data)
410 {
411         FN_START;
412         if (vcard_data == NULL)
413                 return;
414
415         g_free(vcard_data->version);
416         g_free(vcard_data->n);
417         g_free(vcard_data->fn);
418         g_free(vcard_data->tel);
419         g_free(vcard_data->email);
420         g_free(vcard_data);
421         FN_END;
422         return;
423 }
424
425 void bmsg_free_bmsg(struct bmsg_data *bmsg)
426 {
427         FN_START;
428         struct benv_data *env_data;
429         int i = 0;
430
431         if (bmsg == NULL)
432                 return;
433
434         g_free(bmsg->version);
435         g_free(bmsg->status);
436         g_free(bmsg->type);
437         g_free(bmsg->folder);
438         bmsg_free_vcard_data(bmsg->originator_vcard_data);
439
440         if (bmsg->envelope_data == NULL)
441                 goto done;
442
443         if (bmsg->envelope_data->env_data == NULL)
444                 goto done;
445
446         env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i);
447         while (env_data != NULL) {
448
449                 DBG("env_data = %d", env_data->encapsulation_level);
450                 int k = 0;
451                 struct bmsg_vcard *rvcard;
452
453                 rvcard = g_slist_nth_data(env_data->recipient_vcard, k);
454
455                 while (rvcard != NULL) {
456                         k++;
457                         bmsg_free_vcard_data(rvcard);
458                         rvcard = g_slist_nth_data(env_data->recipient_vcard, k);
459                 }
460
461                 if (env_data->body_content != NULL) {
462                         g_free(env_data->body_content->encoding);
463                         g_free(env_data->body_content->charset);
464                         g_free(env_data->body_content->language);
465                         g_free(env_data->body_content->msg);
466                         g_free(env_data->body_content);
467                 }
468
469                 g_free(env_data);
470                 i++;
471
472                 env_data = g_slist_nth_data(bmsg->envelope_data->env_data, i);
473         }
474
475         FN_END;
476 done:
477         g_free(bmsg);
478 }
479
480 gchar *bmsg_get_parse_sub_block(char **sub_block_data, char *element)
481 {
482         FN_START;
483         gchar *start;
484         gchar *end;
485         gchar *block_start;
486         gchar *block_end;
487         gchar *sub_block = NULL;
488         size_t offset;
489         size_t len;
490
491         start = g_strdup_printf("BEGIN:%s\r\n", element);
492         end = g_strdup_printf("END:%s\r\n", element);
493         offset = strlen(start);
494
495         block_start = g_strstr_len(*sub_block_data, offset, start);
496         if (block_start == NULL)
497                 goto done;
498
499         if (!g_strcmp0(start, VCARD_BEGIN_TAG))
500                 block_end = g_strstr_len(*sub_block_data, -1,  end);
501         else
502                 block_end = g_strrstr(*sub_block_data, end);
503
504         if (block_end == NULL)
505                 goto done;
506
507         len = block_end - block_start - offset;
508         sub_block = g_strndup(block_start + offset, len);
509         *sub_block_data = *sub_block_data + strlen(sub_block) + strlen(start) +
510                                                                  strlen(end);
511 done:
512         g_free(start);
513         g_free(end);
514         FN_END;
515         return sub_block;
516 }
517
518 gchar *bmsg_get_tag_data(char **block_data, char *element)
519 {
520         FN_START;
521         gchar *end = "\r\n";
522         gchar *block_start;
523         gchar *block_end;
524         gchar *sub_block;
525         size_t offset;
526         size_t len;
527
528         if (*block_data == NULL || element == NULL)
529                 return NULL;
530
531         block_start = g_strstr_len(*block_data, -1, element);
532         if (block_start == NULL)
533                 return NULL;
534
535         offset = strlen(element);
536
537         block_end = g_strstr_len(block_start+offset, -1, end);
538         if (block_end == NULL)
539                 return NULL;
540
541         len = block_end - block_start - offset;
542         sub_block = g_strndup(block_start + offset, len);
543         *block_data = *block_data + offset + len + CRLF_LEN;
544         FN_END;
545         return sub_block;
546 }
547
548 struct bmsg_bbody *bmsg_get_bbody_data(gchar *block_data)
549 {
550         FN_START;
551         struct bmsg_bbody *bbody;
552         gchar *temp;
553         gchar *bbody_block_data_start = block_data;
554
555         bbody = g_new0(struct bmsg_bbody, 1);
556
557         temp = bmsg_get_tag_data(&block_data, PARTID_TAG);
558         if (temp != NULL) {
559                 bbody->part_id = (guint16)g_ascii_strtoull(temp, NULL, 10);
560                 g_free(temp);
561         }
562
563         bbody->encoding = bmsg_get_tag_data(&block_data, ENCODING_TAG);
564         bbody->charset = bmsg_get_tag_data(&block_data, CHARSET_TAG);
565         bbody->language = bmsg_get_tag_data(&block_data, LANGUAGE_TAG);
566
567         temp = bmsg_get_tag_data(&block_data, LENGTH_TAG);
568
569         if (temp != NULL) {
570                 bbody->length = g_ascii_strtoull(temp, NULL, 10);
571                 g_free(temp);
572         }
573
574         bbody->msg = bmsg_get_parse_sub_block(&block_data, "MSG");
575
576         g_free(bbody_block_data_start);
577         FN_END;
578         return bbody;
579 }
580
581 struct bmsg_vcard *bmsg_get_vcard_data(gchar *sub_block_data)
582 {
583         FN_START;
584         struct bmsg_vcard *vcard;
585         gchar *num;
586         gchar *vcard_block_data_start = sub_block_data;
587
588         vcard = g_new0(struct bmsg_vcard, 1);
589
590         vcard->version = bmsg_get_tag_data(&sub_block_data, VER_TAG);
591         vcard->n = bmsg_get_tag_data(&sub_block_data, VCARD_N_TAG);
592         vcard->fn = bmsg_get_tag_data(&sub_block_data, VCARD_FN_TAG);
593         num = bmsg_get_tag_data(&sub_block_data, VCARD_TEL_TAG);
594         vcard->tel = __bt_get_valid_number(num);
595         vcard->email = bmsg_get_tag_data(&sub_block_data, VCARD_EMAIL_TAG);
596
597         g_free(vcard_block_data_start);
598         g_free(num);
599         FN_END;
600         return vcard;
601 }
602
603 struct benv_data *bmsg_get_env_encapsulation_data(gchar **sub_block_data)
604 {
605         FN_START;
606         gchar *is_valid;
607         gchar *bbody_data = NULL;
608
609         is_valid = g_strstr_len(*sub_block_data, strlen(VCARD_BEGIN_TAG),
610                                                         VCARD_BEGIN_TAG);
611         if (is_valid == NULL)
612                 return NULL;
613
614         if (g_enc_lvl > 3)
615                 return NULL;
616
617         struct benv_data *rec_data = g_new0(struct benv_data, 1);
618
619         rec_data->encapsulation_level = g_enc_lvl;
620         g_enc_lvl++;
621
622         while (is_valid != NULL) {
623                 gchar *vcard_data = NULL;
624                 struct bmsg_vcard *vcard;
625
626                 vcard_data = bmsg_get_parse_sub_block(sub_block_data, "VCARD");
627                 if (vcard_data == NULL) {
628                         ERR("parse error\n");
629                         g_free(rec_data);
630                         return NULL;
631                 }
632                 vcard = bmsg_get_vcard_data(vcard_data);
633
634                 rec_data->recipient_vcard = g_slist_append(
635                                                 rec_data->recipient_vcard,
636                                                 vcard);
637
638                 is_valid = g_strstr_len(*sub_block_data,
639                                                 strlen(VCARD_BEGIN_TAG),
640                                                 VCARD_BEGIN_TAG);
641         }
642
643         is_valid = g_strstr_len(*sub_block_data, strlen(BBODY_TAG), BBODY_TAG);
644
645         if (!is_valid)
646                 return rec_data;
647
648         bbody_data = bmsg_get_parse_sub_block(sub_block_data, "BBODY");
649         if (bbody_data == NULL) {
650                 ERR("parse error\n");
651                 return rec_data;
652         }
653
654         rec_data->body_content = bmsg_get_bbody_data(bbody_data);
655         FN_END;
656         return rec_data;
657 }
658
659 struct bmsg_envelope *bmsg_get_envelope_data(gchar **block_data)
660 {
661         FN_START;
662         gchar *sub_block_data;
663         struct bmsg_envelope *envelope_data;
664         struct benv_data *rec_data;
665
666         envelope_data = g_new0(struct bmsg_envelope, 1);
667
668         sub_block_data = bmsg_get_parse_sub_block(block_data, "BENV");
669
670         while (sub_block_data) {
671                 char *next_sub_block_data;
672                 char *save_sub_block_data = sub_block_data;
673                 rec_data = bmsg_get_env_encapsulation_data(&sub_block_data);
674
675                 while (rec_data) {
676                         envelope_data->env_data = g_slist_append(
677                                                         envelope_data->env_data,
678                                                         rec_data);
679
680                         rec_data = bmsg_get_env_encapsulation_data(
681                                                         &sub_block_data);
682                 }
683                 next_sub_block_data = bmsg_get_parse_sub_block(&sub_block_data,
684                                                                 "BENV");
685                 g_free(save_sub_block_data);
686                 sub_block_data = next_sub_block_data;
687         }
688         g_free(sub_block_data);
689         FN_END;
690         return envelope_data;
691 }
692
693 struct bmsg_data *bmsg_parse(gchar *buf)
694 {
695         FN_START;
696         gchar *block_data;
697         gchar *sub_block_data;
698         gchar *block_data_start;
699         struct bmsg_data *bmsg;
700
701         g_enc_lvl = 1;
702
703         block_data = bmsg_get_parse_sub_block(&buf, "BMSG");
704         if (block_data == NULL)
705                 return NULL;
706
707         block_data_start = block_data;
708
709         bmsg = g_new0(struct bmsg_data, 1);
710
711         bmsg->version = bmsg_get_tag_data(&block_data, VER_TAG);
712         if (bmsg->version == NULL)
713                 goto parse_fail;
714
715         bmsg->status = bmsg_get_tag_data(&block_data, STATUS_TAG);
716         if (bmsg->status == NULL)
717                 goto parse_fail;
718
719         bmsg->type = bmsg_get_tag_data(&block_data, TYPE_TAG);
720         if (bmsg->type == NULL)
721                 goto parse_fail;
722
723         bmsg->folder = bmsg_get_tag_data(&block_data, FOLDER_TAG);
724         if (bmsg->folder == NULL)
725                 goto parse_fail;
726
727         sub_block_data = bmsg_get_parse_sub_block(&block_data, "VCARD");
728         if (sub_block_data != NULL) {
729                 bmsg->originator_vcard_data = bmsg_get_vcard_data(sub_block_data);
730                 if (bmsg->originator_vcard_data == NULL)
731                         goto parse_fail;
732         }
733
734         bmsg->envelope_data = bmsg_get_envelope_data(&block_data);
735         if (bmsg->envelope_data == NULL)
736                 goto parse_fail;
737
738         g_free(block_data_start);
739
740         DBG("Parse done");
741         print_bmsg(bmsg);
742         FN_END;
743         return bmsg;
744
745 parse_fail:
746         g_free(block_data_start);
747
748         ERR("Parse fail");
749         bmsg_free_bmsg(bmsg);
750         FN_END;
751         return NULL;
752 }
753 /* LCOV_EXCL_STOP */