Fixes for build errors hit by some versions of Visual Studio
[platform/upstream/iotivity.git] / resource / csdk / stack / src / oicgroup.c
1 //******************************************************************
2 //
3 // Copyright 2014 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #define _POSIX_C_SOURCE 200112L
22
23 #include "iotivity_config.h"
24
25 #include <string.h>
26
27 #include "oicgroup.h"
28 #include "cJSON.h"
29 #include "cbor.h"
30 #include "ocpayload.h"
31 #include "oic_malloc.h"
32 #include "oic_string.h"
33 #include "occollection.h"
34 #include "logger.h"
35 #include "timer.h"
36
37 #define TAG "OIC_RI_GROUP"
38
39 #define DESC_DELIMITER          "\""
40 #define ACTION_DELIMITER        "*"
41 #define ATTR_DELIMITER          "|"
42 #define ATTR_ASSIGN             "="
43
44 // Definitions for operations related to actions
45 #define DO_ACTION               "DoAction"
46 #define GET_ACTIONSET           "GetActionSet"
47 #define ACTIONSET               "ActionSet"
48 #define CANCEL_ACTIONSET        "CancelAction"
49 #define DELETE_ACTIONSET        "DelActionSet"
50
51 #define DEFAULT_CONTEXT_VALUE 0x99
52
53 #define VARIFY_POINTER_NULL(pointer, result, toExit) \
54     if(pointer == NULL) \
55     {\
56         result = OC_STACK_NO_MEMORY;\
57         goto toExit;\
58     }
59 #define VARIFY_PARAM_NULL(pointer, result, toExit) \
60     if(pointer == NULL)\
61     {\
62         result = OC_STACK_INVALID_PARAM;\
63         goto exit;\
64     }
65
66 #define OCFREE(pointer) \
67     { \
68         OICFree(pointer); \
69         pointer = NULL; \
70     }
71
72 // Mutex implementation macros
73 #if defined(HAVE_PTHREAD_H)
74
75  #include <pthread.h>
76  pthread_mutex_t lock;
77  #define MUTEX_LOCK(ARG_NAME)    { pthread_mutex_lock(ARG_NAME); }
78  #define MUTEX_UNLOCK(ARG_NAME)  { pthread_mutex_unlock(ARG_NAME); }
79
80 #elif defined(HAVE_WINDOWS_H)
81
82  #include <windows.h>
83  CRITICAL_SECTION lock;
84  #define MUTEX_LOCK(ARG_NAME)   { EnterCriticalSection(ARG_NAME); }
85  #define MUTEX_UNLOCK(ARG_NAME) { LeaveCriticalSection(ARG_NAME); }
86
87 #elif defined(WITH_ARDUINO)
88
89  #define MUTEX_LOCK(ARG_NAME)   {  }
90  #define MUTEX_UNLOCK(ARG_NAME) {  }
91
92 #else
93
94  ERROR Need mutex implementation on this platform
95
96 #endif
97
98 enum ACTION_TYPE
99 {
100     NONE = 0, SCHEDULED, RECURSIVE
101 };
102
103 typedef struct scheduledresourceinfo
104 {
105     OCResource *resource;
106     OCActionSet *actionset;
107
108     int timer_id;
109
110     OCServerRequest *ehRequest;
111
112     time_t time;
113     struct scheduledresourceinfo* next;
114 } ScheduledResourceInfo;
115
116 ScheduledResourceInfo *scheduleResourceList = NULL;
117
118 void AddScheduledResource(ScheduledResourceInfo **head,
119         ScheduledResourceInfo* add)
120 {
121     OIC_LOG(INFO, TAG, "AddScheduledResource Entering...");
122
123     MUTEX_LOCK(&lock);
124     ScheduledResourceInfo *tmp = NULL;
125
126     if (*head != NULL)
127     {
128         tmp = *head;
129
130         while (tmp->next)
131         {
132             tmp = tmp->next;
133         }
134         tmp->next = add;
135     }
136     else
137     {
138         *head = add;
139     }
140     MUTEX_UNLOCK(&lock);
141 }
142
143 ScheduledResourceInfo* GetScheduledResource(ScheduledResourceInfo *head)
144 {
145     OIC_LOG(INFO, TAG, "GetScheduledResource Entering...");
146
147     MUTEX_LOCK(&lock);
148
149     time_t t_now;
150
151     ScheduledResourceInfo *tmp = NULL;
152     tmp = head;
153
154 #if !defined(WITH_ARDUINO)
155     time(&t_now);
156 #else
157     t_now = now();
158 #endif
159
160     if (tmp)
161     {
162         while (tmp)
163         {
164             time_t diffTm = 0;
165             diffTm = timespec_diff(tmp->time, t_now);
166
167             if (diffTm <= (time_t) 0)
168             {
169                 OIC_LOG(INFO, TAG, "return Call INFO.");
170                 goto exit;
171             }
172
173             tmp = tmp->next;
174         }
175     }
176
177     exit:
178
179     MUTEX_UNLOCK(&lock);
180
181     if (tmp == NULL)
182     {
183         OIC_LOG(INFO, TAG, "Cannot Find Call Info.");
184     }
185     return tmp;
186 }
187
188 ScheduledResourceInfo* GetScheduledResourceByActionSetName(ScheduledResourceInfo *head, char *setName)
189 {
190     OIC_LOG(INFO, TAG, "GetScheduledResourceByActionSetName Entering...");
191
192     MUTEX_LOCK(&lock);
193
194     ScheduledResourceInfo *tmp = NULL;
195     tmp = head;
196
197     if (tmp)
198     {
199         while (tmp)
200         {
201             if (strcmp(tmp->actionset->actionsetName, setName) == 0)
202             {
203                 OIC_LOG(INFO, TAG, "return Call INFO.");
204                 goto exit;
205             }
206             tmp = tmp->next;
207         }
208     }
209
210 exit:
211
212     MUTEX_UNLOCK(&lock);
213
214     if (tmp == NULL)
215     {
216         OIC_LOG(INFO, TAG, "Cannot Find Call Info.");
217     }
218     return tmp;
219 }
220
221 void RemoveScheduledResource(ScheduledResourceInfo **head,
222         ScheduledResourceInfo* del)
223 {
224
225     MUTEX_LOCK(&lock);
226
227     OIC_LOG(INFO, TAG, "RemoveScheduledResource Entering...");
228     ScheduledResourceInfo *tmp = NULL;
229
230     if (del == NULL)
231     {
232
233         MUTEX_UNLOCK(&lock);
234
235         return;
236     }
237
238     if (*head == del)
239     {
240         *head = (*head)->next;
241     }
242     else
243     {
244         tmp = *head;
245         while (tmp->next && (tmp->next != del))
246         {
247             tmp = tmp->next;
248         }
249         if (tmp->next)
250         {
251             tmp->next = del->next;
252         }
253     }
254
255     OCFREE(del)
256
257     MUTEX_UNLOCK(&lock);
258
259 }
260
261 typedef struct aggregatehandleinfo
262 {
263     OCServerRequest *ehRequest;
264     OCDoHandle required;
265     OCResource *collResource;
266
267     struct aggregatehandleinfo *next;
268 } ClientRequestInfo;
269
270 ClientRequestInfo *clientRequstList = NULL;
271
272 void AddClientRequestInfo(ClientRequestInfo **head, ClientRequestInfo* add)
273 {
274     ClientRequestInfo *tmp = NULL;
275
276     if (*head != NULL)
277     {
278         tmp = *head;
279
280         while (tmp->next)
281         {
282             tmp = tmp->next;
283         }
284         tmp->next = add;
285     }
286     else
287     {
288         *head = add;
289     }
290 }
291
292 ClientRequestInfo* GetClientRequestInfo(ClientRequestInfo *head,
293         OCDoHandle handle)
294 {
295     ClientRequestInfo *tmp = NULL;
296
297     tmp = head;
298
299     if (tmp)
300     {
301         while (tmp)
302         {
303             if (tmp->required == handle)
304             {
305                 break;
306             }
307
308             tmp = tmp->next;
309         }
310
311         return tmp;
312     }
313     return NULL;
314 }
315
316 void RemoveClientRequestInfo(ClientRequestInfo **head, ClientRequestInfo* del)
317 {
318     ClientRequestInfo *tmp = NULL;
319
320     if (del == NULL)
321         return;
322
323     if (*head == del)
324     {
325         *head = (*head)->next;
326     }
327     else
328     {
329         tmp = *head;
330         while (tmp->next && (tmp->next != del))
331         {
332             tmp = tmp->next;
333         }
334         if (tmp->next)
335         {
336             tmp->next = del->next;
337         }
338     }
339 }
340
341 void AddCapability(OCCapability** head, OCCapability* node)
342 {
343     OCCapability *pointer = *head;
344     if (NULL == pointer)
345     {
346         *head = node;
347     }
348     else
349     {
350         while (pointer->next != NULL)
351         {
352             pointer = pointer->next;
353         }
354
355         pointer->next = node;
356     }
357 }
358
359 void AddAction(OCAction** head, OCAction* node)
360 {
361     OCAction *pointer = *head;
362     if (NULL == pointer)
363     {
364         *head = node;
365     }
366     else
367     {
368
369         while (pointer->next != NULL)
370         {
371             pointer = pointer->next;
372         }
373
374         pointer->next = node;
375     }
376 }
377
378 OCStackResult AddActionSet(OCActionSet **head, OCActionSet* node)
379 {
380     OCActionSet *pointer = *head;
381     OCActionSet *prev = NULL;
382     if(node == NULL)
383     {
384         return OC_STACK_ERROR;
385     }
386     if (NULL == pointer)
387     {
388         *head = node;
389     }
390     else
391     {
392         prev = pointer;
393         while (pointer != NULL)
394         {
395             // check the uniqeness of actionsetname.
396             if (strcmp(pointer->actionsetName, node->actionsetName) == 0)
397             {
398                 return OC_STACK_ERROR;
399             }
400
401             prev = pointer;
402             pointer = pointer->next;
403         }
404
405         prev->next = node;
406     }
407
408     return OC_STACK_OK;
409 }
410
411 void DeleteCapability(OCCapability *del)
412 {
413     OCFREE(del->capability)
414     del->capability = NULL;
415     OCFREE(del->status)
416     del->status = NULL;
417     OCFREE(del)
418 }
419
420 void DeleteAction(OCAction** action)
421 {
422     OCCapability* pointer = (*action)->head;
423     OCCapability* pDel = NULL;
424
425     while (pointer)
426     {
427         pDel = pointer;
428         pointer = pointer->next;
429
430         DeleteCapability(pDel);
431     }
432     OCFREE((*action)->resourceUri)
433     (*action)->next = NULL;
434     OCFREE(*action)
435 }
436
437 void DeleteActionSet(OCActionSet** actionset)
438 {
439     OCAction* pointer = NULL;
440     OCAction* pDel = NULL;
441
442     if(*actionset == NULL)
443         return;
444
445     pointer = (*actionset)->head;
446
447     while (pointer)
448     {
449         pDel = pointer;
450         pointer = pointer->next;
451
452         DeleteAction(&pDel);
453     }
454     //    (*actionset)->head = NULL;
455     OCFREE((*actionset)->actionsetName)
456     OCFREE(*actionset)
457 }
458
459 OCStackResult FindAndDeleteActionSet(OCResource **resource,
460         const char * actionsetName)
461 {
462     if (*resource != NULL)
463     {
464         OCActionSet *pointer = NULL;
465         OCActionSet *pDel = NULL;
466
467         pointer = (*resource)->actionsetHead;
468
469         if (pointer == NULL)
470         {
471             return OC_STACK_ERROR;
472         }
473         else
474         {
475             if (strcmp(pointer->actionsetName, actionsetName) == 0)
476             {
477                 if (pointer->next != NULL)
478                     (*resource)->actionsetHead = pointer->next;
479                 else
480                     (*resource)->actionsetHead = NULL;
481
482                 DeleteActionSet(&pointer);
483             }
484             else if (pointer->next != NULL)
485             {
486                 while (pointer)
487                 {
488                     if (pointer->next != NULL)
489                     {
490                         if (strcmp(pointer->next->actionsetName, actionsetName)
491                                 == 0)
492                         {
493                             pDel = pointer->next;
494                             pointer->next = pointer->next->next;
495
496                             DeleteActionSet(&pDel);
497                         }
498                     }
499                     pointer = pointer->next;
500                 }
501             }
502
503             return OC_STACK_OK;
504         }
505
506     }
507     return OC_STACK_ERROR;
508 }
509
510 OCStackResult GetActionSet(const char *actionName, OCActionSet *head,
511         OCActionSet** actionset)
512 {
513     OCActionSet *pointer = head;
514
515     while (pointer)
516     {
517         if (strcmp(pointer->actionsetName, actionName) == 0)
518         {
519             *actionset = pointer;
520             return OC_STACK_OK;
521         }
522
523         pointer = pointer->next;
524     }
525
526     return OC_STACK_ERROR;
527
528 }
529
530 OCStackResult ExtractKeyValueFromRequest(OCEntityHandlerRequest *ehRequest,
531                                         char **key, char **value)
532 {
533     OCStackResult result = OC_STACK_OK;
534
535     char *actionSetStr = NULL;
536
537     if( NULL == ehRequest->payload )
538     {
539         result = OC_STACK_ERROR;
540         goto exit;
541     }
542
543     OCRepPayload* input;
544
545     input = (OCRepPayload*)(ehRequest->payload);
546
547     if(OCRepPayloadGetPropString(input, ACTIONSET, &actionSetStr))
548     {
549         *key = OICStrdup(ACTIONSET);
550         VARIFY_POINTER_NULL(*key, result, exit);
551
552         *value = OICStrdup(actionSetStr);
553         VARIFY_POINTER_NULL(*value, result, exit);
554     }
555     else if(OCRepPayloadGetPropString(input, DO_ACTION, &actionSetStr))
556     {
557         *key = OICStrdup(DO_ACTION);
558         VARIFY_POINTER_NULL(*key, result, exit);
559
560         *value = OICStrdup(actionSetStr);
561         VARIFY_POINTER_NULL(*value, result, exit);
562     }
563     else if(OCRepPayloadGetPropString(input, GET_ACTIONSET, &actionSetStr))
564     {
565         *key = OICStrdup(GET_ACTIONSET);
566         VARIFY_POINTER_NULL(*key, result, exit);
567
568         *value = OICStrdup(actionSetStr);
569         VARIFY_POINTER_NULL(*value, result, exit);
570     }
571     else if(OCRepPayloadGetPropString(input, DELETE_ACTIONSET, &actionSetStr))
572     {
573         *key = OICStrdup(DELETE_ACTIONSET);
574         VARIFY_POINTER_NULL(*key, result, exit);
575
576         *value = OICStrdup(actionSetStr);
577         VARIFY_POINTER_NULL(*value, result, exit);
578     }
579     else if(OCRepPayloadGetPropString(input, CANCEL_ACTIONSET, &actionSetStr))
580     {
581         *key = OICStrdup(CANCEL_ACTIONSET);
582         VARIFY_POINTER_NULL(*key, result, exit);
583
584         *value = OICStrdup(actionSetStr);
585         VARIFY_POINTER_NULL(*value, result, exit);
586     }
587     else
588     {
589         result = OC_STACK_ERROR;
590     }
591
592 exit:
593     if (result != OC_STACK_OK)
594     {
595         OCFREE(*key)
596         OCFREE(*value)
597     }
598
599     OCFREE(actionSetStr);
600
601     return result;
602 }
603
604 OCStackResult ExtractActionSetNameAndDelaytime(char *pChar, char **setName,
605         long int *pa)
606 {
607     char *token = NULL, *tokenPtr = NULL;
608     OCStackResult result = OC_STACK_OK;
609
610     token = (char*) strtok_r(pChar, ACTION_DELIMITER, &tokenPtr);
611     VARIFY_POINTER_NULL(token, result, exit)
612
613     *setName = (char *) OICMalloc(strlen(token) + 1);
614     VARIFY_POINTER_NULL(*setName, result, exit)
615     VARIFY_PARAM_NULL(token, result, exit)
616     strncpy(*setName, token, strlen(token) + 1);
617
618     token = strtok_r(NULL, ACTION_DELIMITER, &tokenPtr);
619     VARIFY_POINTER_NULL(pa, result, exit)
620     VARIFY_PARAM_NULL(token, result, exit)
621     *pa = atoi(token);
622
623     return OC_STACK_OK;
624
625 exit:
626     OCFREE(*setName);
627     return result;
628 }
629
630 OCStackResult BuildActionSetFromString(OCActionSet **set, char* actiondesc)
631 {
632     OCStackResult result = OC_STACK_OK;
633
634     char *iterToken = NULL, *iterTokenPtr = NULL;
635     char *descIterToken = NULL, *descIterTokenPtr = NULL;
636     char *attrIterToken = NULL, *attrIterTokenPtr = NULL;
637     char *desc = NULL, *attr = NULL;
638     char *key = NULL, *value = NULL;
639
640     OCAction *action = NULL;
641     OCCapability *capa = NULL;
642
643     OIC_LOG(INFO, TAG, "Build ActionSet Instance.");
644
645     *set = (OCActionSet*) OICMalloc(sizeof(OCActionSet));
646     VARIFY_POINTER_NULL(*set, result, exit)
647
648     iterToken = (char *) strtok_r(actiondesc, ACTION_DELIMITER, &iterTokenPtr);
649     VARIFY_POINTER_NULL(iterToken, result, exit);
650
651     // ActionSet Name
652     memset(*set, 0, sizeof(OCActionSet));
653     (*set)->actionsetName = (char *) OICMalloc(strlen(iterToken) + 1);
654     VARIFY_POINTER_NULL((*set)->actionsetName, result, exit)
655     VARIFY_PARAM_NULL(iterToken, result, exit)
656     strncpy((*set)->actionsetName, iterToken, strlen(iterToken) + 1);
657
658     // Time info. for Scheduled/Recursive Group action.
659     // d is meant Day of the week.
660     // T is meant ActionType.
661     // yyyy-mm-dd hh:mm:ss d
662     iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
663     VARIFY_PARAM_NULL(iterToken, result, exit)
664 #if !defined(WITH_ARDUINO)
665     if( 2 != sscanf(iterToken, "%ld %u", &(*set)->timesteps, &(*set)->type) )
666     {
667         // If the return value should be 2, the number of items in the argument. Otherwise, it fails.
668         goto exit;
669     }
670 #endif
671
672     OIC_LOG_V(INFO, TAG, "ActionSet Name : %s", (*set)->actionsetName);
673
674     iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
675     while (iterToken)
676     {
677         desc = (char *) OICMalloc(strlen(iterToken) + 1);
678         VARIFY_POINTER_NULL(desc, result, exit)
679         VARIFY_PARAM_NULL(desc, result, exit)
680         strncpy(desc, iterToken, strlen(iterToken) + 1);
681         descIterToken = (char *) strtok_r(desc, ATTR_DELIMITER,
682                 &descIterTokenPtr);
683         while (descIterToken)
684         {
685             attr = (char *) OICMalloc(strlen(descIterToken) + 1);
686             VARIFY_POINTER_NULL(attr, result, exit)
687             VARIFY_PARAM_NULL(descIterToken, result, exit)
688             strncpy(attr, descIterToken, strlen(descIterToken) + 1);
689
690             attrIterToken = (char *) strtok_r(attr, ATTR_ASSIGN,
691                     &attrIterTokenPtr);
692             VARIFY_POINTER_NULL(attrIterToken, result, exit);
693
694             key = (char *) OICMalloc(strlen(attrIterToken) + 1);
695             VARIFY_POINTER_NULL(key, result, exit)
696             VARIFY_PARAM_NULL(attrIterToken, result, exit)
697             strncpy(key, attrIterToken, strlen(attrIterToken) + 1);
698
699             attrIterToken = (char *) strtok_r(NULL, ATTR_ASSIGN,
700                     &attrIterTokenPtr);
701             VARIFY_POINTER_NULL(attrIterToken, result, exit);
702             value = (char *) OICMalloc(strlen(attrIterToken) + 1);
703             VARIFY_POINTER_NULL(value, result, exit)
704             VARIFY_PARAM_NULL(attrIterToken, result, exit)
705             strncpy(value, attrIterToken, strlen(attrIterToken) + 1);
706
707             if (strcmp(key, "uri") == 0)
708             {
709                 OIC_LOG(INFO, TAG, "Build OCAction Instance.");
710
711                 action = (OCAction*) OICMalloc(sizeof(OCAction));
712                 VARIFY_POINTER_NULL(action, result, exit)
713                 memset(action, 0, sizeof(OCAction));
714                 action->resourceUri = (char *) OICMalloc(strlen(value) + 1);
715                 VARIFY_POINTER_NULL(action->resourceUri, result, exit)
716                 VARIFY_PARAM_NULL(value, result, exit)
717                 strncpy(action->resourceUri, value, strlen(value) + 1);
718             }
719             else
720             {
721                 if ((key != NULL) && (value != NULL))
722                 {
723                     OIC_LOG(INFO, TAG, "Build OCCapability Instance.");
724
725                     capa = (OCCapability*) OICMalloc(sizeof(OCCapability));
726                     VARIFY_POINTER_NULL(capa, result, exit)
727                     memset(capa, 0, sizeof(OCCapability));
728
729                     capa->capability = (char *) OICMalloc(strlen(key) + 1);
730                     VARIFY_POINTER_NULL(capa->capability, result, exit)
731                     VARIFY_PARAM_NULL(key, result, exit)
732                     strncpy(capa->capability, key, strlen(key) + 1);
733
734                     capa->status = (char *) OICMalloc(strlen(value) + 1);
735                     VARIFY_POINTER_NULL(capa->status, result, exit)
736                     VARIFY_PARAM_NULL(value, result, exit)
737                     strncpy(capa->status, value, strlen(value) + 1);
738
739                     VARIFY_POINTER_NULL(action, result, exit)
740
741                     AddCapability(&action->head, capa);
742                 }
743             }
744
745             OCFREE(key)
746             OCFREE(value)
747             OCFREE(attr)
748
749             descIterToken = (char *) strtok_r(NULL, ATTR_DELIMITER,
750                     &descIterTokenPtr);
751         }
752
753         AddAction(&(*set)->head, action);
754         iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
755         OCFREE(desc);
756     }
757
758     return OC_STACK_OK;
759 exit:
760     OCFREE(attr)
761     OCFREE(desc)
762     OCFREE(capa)
763     OCFREE(action)
764     OCFREE(*set)
765     OCFREE(key)
766     OCFREE(value)
767     OCFREE(attr)
768
769     return result;
770 }
771
772 OCStackResult BuildStringFromActionSet(OCActionSet* actionset, char** desc)
773 {
774     // Can't use the macros here as they are hardcoded to 'exit' and will
775     // result in dereferencing a null pointer.
776     if (!actionset || !desc)
777     {
778         return OC_STACK_INVALID_PARAM;
779     }
780     char temp[1024] = { 0 };
781     size_t remaining = sizeof(temp) - 1;
782     OCStackResult res = OC_STACK_ERROR;
783     char* actionTypeStr = NULL;
784
785     OCAction *action = actionset->head;
786
787     if (remaining >= strlen(actionset->actionsetName) + 1)
788     {
789         strncat(temp, actionset->actionsetName, strlen(actionset->actionsetName));
790         remaining -= strlen(actionset->actionsetName);
791         strncat(temp, ACTION_DELIMITER, strlen(ACTION_DELIMITER));
792         remaining--;
793     }
794     else
795     {
796         res = OC_STACK_ERROR;
797         goto exit;
798     }
799
800     actionTypeStr = (char *)malloc(1024);
801     if(actionTypeStr != NULL)
802     {
803         sprintf(actionTypeStr, "%ld %u", actionset->timesteps, actionset->type);
804         if(remaining >= strlen(actionTypeStr) + strlen(ACTION_DELIMITER) + 1)
805         {
806             strncat(temp, actionTypeStr, strlen(actionTypeStr));
807             remaining -= strlen(actionTypeStr);
808             strncat(temp, ACTION_DELIMITER, strlen(ACTION_DELIMITER));
809             remaining -= strlen(ACTION_DELIMITER);
810             free(actionTypeStr);
811         }
812         else
813         {
814             free(actionTypeStr);
815             res = OC_STACK_ERROR;
816             goto exit;
817         }
818     }
819     else
820     {
821         res = OC_STACK_ERROR;
822         goto exit;
823     }
824
825     while (action != NULL)
826     {
827         if (remaining < (strlen("uri=") + strlen(action->resourceUri) + 1))
828         {
829             res = OC_STACK_ERROR;
830             goto exit;
831         }
832
833         strcat(temp, "uri=");
834         remaining -= strlen("uri=");
835         strcat(temp, action->resourceUri);
836         remaining -= strlen(action->resourceUri);
837         strcat(temp, "|");
838         remaining--;
839
840         OCCapability *capas = action->head;
841         while (capas != NULL)
842         {
843             if (remaining < (strlen(capas->capability)
844                              + 1 + strlen(capas->status)))
845             {
846                 res = OC_STACK_ERROR;
847                 goto exit;
848             }
849
850             strcat(temp, capas->capability);
851             remaining -= strlen(capas->capability);
852             strcat(temp, "=");
853             remaining--;
854             strcat(temp, capas->status);
855             remaining -= strlen(capas->status);
856
857             capas = capas->next;
858             if (capas != NULL)
859             {
860                 if (remaining < 1)
861                 {
862                     res = OC_STACK_ERROR;
863                     goto exit;
864                 }
865                 strcat(temp, "|");
866                 remaining --;
867             }
868         }
869
870         action = action->next;
871         if (action != NULL)
872         {
873             if (remaining < strlen(ACTION_DELIMITER))
874             {
875                 res = OC_STACK_ERROR;
876                 goto exit;
877             }
878             strcat(temp, ACTION_DELIMITER);
879             remaining--;
880         }
881     }
882
883     *desc = OICStrdup(temp);
884     VARIFY_POINTER_NULL(*desc, res, exit);
885
886     return OC_STACK_OK;
887
888 exit:
889     OCFREE(*desc);
890     return res;
891 }
892
893 OCStackApplicationResult ActionSetCB(void* context, OCDoHandle handle,
894         OCClientResponse* clientResponse)
895 {
896     (void)context;
897     (void)clientResponse;
898     OIC_LOG(INFO, TAG, "Entering ActionSetCB");
899
900     ClientRequestInfo *info = GetClientRequestInfo(clientRequstList, handle);
901
902     if (info)
903     {
904         OCEntityHandlerResponse response = { 0 };
905
906         response.ehResult = OC_EH_OK;
907
908         if(NULL == clientResponse->payload)
909         {
910             OIC_LOG(ERROR, TAG, "Error sending response");
911             return OC_STACK_DELETE_TRANSACTION;
912         }
913
914         // Format the response.  Note this requires some info about the request
915         response.requestHandle = info->ehRequest;
916         response.resourceHandle = info->collResource;
917         response.payload = clientResponse->payload;
918         response.numSendVendorSpecificHeaderOptions = 0;
919         memset(response.sendVendorSpecificHeaderOptions, 0,
920                 sizeof response.sendVendorSpecificHeaderOptions);
921         memset(response.resourceUri, 0, sizeof response.resourceUri);
922         // Indicate that response is NOT in a persistent buffer
923         response.persistentBufferFlag = 0;
924
925         // Send the response
926         if (OCDoResponse(&response) != OC_STACK_OK)
927         {
928             OIC_LOG(ERROR, TAG, "Error sending response");
929             return OC_STACK_DELETE_TRANSACTION;
930         }
931
932         RemoveClientRequestInfo(&clientRequstList, info);
933         OCFREE(info)
934     }
935
936     return OC_STACK_KEEP_TRANSACTION;
937 }
938
939 void ActionSetCD(void *context)
940 {
941     (void)context;
942 }
943
944 OCStackResult BuildActionJSON(OCAction* action, unsigned char* bufferPtr,
945         uint16_t *remaining)
946 {
947     OCStackResult ret = OC_STACK_ERROR;
948     cJSON *json;
949     cJSON *body;
950
951     char *jsonStr;
952     uint16_t jsonLen;
953
954     OIC_LOG(INFO, TAG, "Entering BuildActionJSON");
955     json = cJSON_CreateObject();
956
957     cJSON_AddItemToObject(json, "rep", body = cJSON_CreateObject());
958
959     OCCapability* pointerCapa = action->head;
960     while (pointerCapa)
961     {
962         cJSON_AddStringToObject(body, pointerCapa->capability,
963                 pointerCapa->status);
964         pointerCapa = pointerCapa->next;
965     }
966
967     jsonStr = cJSON_PrintUnformatted(json);
968
969     jsonLen = strlen(jsonStr);
970     if (jsonLen < *remaining)
971     {
972         strncat((char*) bufferPtr, jsonStr, jsonLen);
973         *remaining -= jsonLen;
974         bufferPtr += jsonLen;
975         ret = OC_STACK_OK;
976     }
977
978     cJSON_Delete(json);
979     free(jsonStr);
980
981     return ret;
982 }
983
984 OCPayload* BuildActionCBOR(OCAction* action)
985 {
986     OCRepPayload* payload = OCRepPayloadCreate();
987
988     if (!payload)
989     {
990         OIC_LOG(INFO, TAG, "Failed to create put payload object");
991         return NULL;
992     }
993
994     OCCapability* pointerCapa = action->head;
995     while (pointerCapa)
996     {
997         OCRepPayloadSetPropString(payload, pointerCapa->capability, pointerCapa->status);
998         pointerCapa = pointerCapa->next;
999     }
1000
1001     return (OCPayload*) payload;
1002 }
1003
1004 unsigned int GetNumOfTargetResource(OCAction *actionset)
1005 {
1006     int numOfResource = 0;
1007
1008     OCAction *pointerAction = actionset;
1009
1010     while (pointerAction != NULL)
1011     {
1012         numOfResource++;
1013         pointerAction = pointerAction->next;
1014     }
1015
1016     return numOfResource;
1017 }
1018
1019 OCStackResult SendAction(OCDoHandle *handle, OCServerRequest* requestHandle, const char *targetUri,
1020         OCPayload *payload)
1021 {
1022
1023     OCCallbackData cbData;
1024     cbData.cb = &ActionSetCB;
1025     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
1026     cbData.cd = NULL;
1027
1028     return OCDoResource(handle, OC_REST_PUT, targetUri, &requestHandle->devAddr,
1029                        payload, CT_ADAPTER_IP, OC_NA_QOS, &cbData, NULL, 0);
1030 }
1031
1032 OCStackResult DoAction(OCResource* resource, OCActionSet* actionset,
1033         OCServerRequest* requestHandle)
1034 {
1035     OCStackResult result = OC_STACK_ERROR;
1036
1037     if( NULL == actionset->head)
1038     {
1039         return result;
1040     }
1041
1042     OCAction *pointerAction = actionset->head;
1043
1044     while (pointerAction != NULL)
1045     {
1046         OCPayload* payload;
1047         payload = BuildActionCBOR(pointerAction);
1048
1049         if(payload == NULL)
1050         {
1051             return result;
1052         }
1053
1054         ClientRequestInfo *info = (ClientRequestInfo *) OICMalloc(
1055                 sizeof(ClientRequestInfo));
1056
1057         if( info == NULL )
1058         {
1059             OCFREE(payload);
1060             return OC_STACK_NO_MEMORY;
1061         }
1062
1063         memset(info, 0, sizeof(ClientRequestInfo));
1064
1065         info->collResource = resource;
1066         info->ehRequest = requestHandle;
1067
1068         result = SendAction(&info->required, info->ehRequest, pointerAction->resourceUri,
1069                 payload);
1070
1071         if (result != OC_STACK_OK)
1072         {
1073             OICFree(info);
1074             return result;
1075         }
1076
1077         AddClientRequestInfo(&clientRequstList, info);
1078
1079         pointerAction = pointerAction->next;
1080     }
1081
1082     return result;
1083 }
1084
1085 void DoScheduledGroupAction()
1086 {
1087     OIC_LOG(INFO, TAG, "DoScheduledGroupAction Entering...");
1088     ScheduledResourceInfo* info = GetScheduledResource(scheduleResourceList);
1089
1090     if (info == NULL)
1091     {
1092         OIC_LOG(INFO, TAG, "Target resource is NULL");
1093         goto exit;
1094     }
1095     else if (info->resource == NULL)
1096     {
1097         OIC_LOG(INFO, TAG, "Target resource is NULL");
1098         goto exit;
1099     }
1100     else if (info->actionset == NULL)
1101     {
1102         OIC_LOG(INFO, TAG, "Target ActionSet is NULL");
1103         goto exit;
1104     }
1105     else if (info->ehRequest == NULL)
1106     {
1107         OIC_LOG(INFO, TAG, "Target ActionSet is NULL");
1108         goto exit;
1109     }
1110
1111     MUTEX_LOCK(&lock);
1112
1113     DoAction(info->resource, info->actionset, info->ehRequest);
1114
1115     MUTEX_UNLOCK(&lock);
1116
1117
1118     if (info->actionset->type == RECURSIVE)
1119     {
1120         ScheduledResourceInfo *schedule;
1121         schedule = (ScheduledResourceInfo *) OICMalloc(
1122                 sizeof(ScheduledResourceInfo));
1123
1124         if (schedule)
1125         {
1126             OIC_LOG(INFO, TAG, "Building New Call Info.");
1127             memset(schedule, 0, sizeof(ScheduledResourceInfo));
1128
1129             if (info->actionset->timesteps > 0)
1130             {
1131                 MUTEX_LOCK(&lock);
1132                 schedule->resource = info->resource;
1133                 schedule->actionset = info->actionset;
1134                 schedule->ehRequest = info->ehRequest;
1135
1136                 schedule->time = registerTimer(info->actionset->timesteps,
1137                         &schedule->timer_id,
1138                         &DoScheduledGroupAction);
1139
1140                 OIC_LOG(INFO, TAG, "Reregisteration.");
1141                 MUTEX_UNLOCK(&lock);
1142                 AddScheduledResource(&scheduleResourceList, schedule);
1143             }
1144             else
1145             {
1146                 OICFree(schedule);
1147             }
1148         }
1149     }
1150
1151     RemoveScheduledResource(&scheduleResourceList, info);
1152
1153     exit:
1154
1155     return;
1156 }
1157
1158 OCStackResult BuildCollectionGroupActionCBORResponse(
1159         OCMethod method/*OCEntityHandlerFlag flag*/, OCResource *resource,
1160         OCEntityHandlerRequest *ehRequest)
1161 {
1162     OCStackResult stackRet = OC_STACK_ERROR;
1163
1164     OIC_LOG(INFO, TAG, "Group Action is requested.");
1165
1166     char *doWhat = NULL;
1167     char *details = NULL;
1168
1169 #if defined(_WIN32)
1170     static bool initializedCriticalSection = false;
1171
1172     if(false == initializedCriticalSection) {
1173         /** @todo Find a way to DeleteCriticalSection somewhere. */
1174         InitializeCriticalSection(&lock);
1175         initializedCriticalSection = true;
1176     }
1177 #endif
1178
1179     stackRet = ExtractKeyValueFromRequest(ehRequest, &doWhat, &details);
1180
1181     if(stackRet != OC_STACK_OK)
1182     {
1183         OIC_LOG_V(ERROR, TAG, "ExtractKeyValueFromRequest failed: %d", stackRet);
1184         return stackRet;
1185     }
1186
1187     stackRet = OC_STACK_ERROR;
1188
1189     if (method == OC_REST_PUT)
1190     {
1191         OIC_LOG(INFO, TAG, "Group Action[PUT].");
1192
1193         if (strcmp(doWhat, ACTIONSET) == 0)
1194         {
1195             OCActionSet *actionSet = NULL;
1196             stackRet = BuildActionSetFromString(&actionSet, details);
1197
1198             if(stackRet == OC_STACK_OK)
1199             {
1200                 if (actionSet != NULL)
1201                 {
1202                     stackRet = AddActionSet(&resource->actionsetHead,
1203                             actionSet);
1204                     if (stackRet == OC_STACK_ERROR)
1205                     {
1206                         if(actionSet != NULL)
1207                         {
1208                             DeleteActionSet( &actionSet );
1209                         }
1210                         OIC_LOG(INFO, TAG, "Duplicated ActionSet ");
1211                     }
1212                 }
1213                 else
1214                 {
1215                     stackRet = OC_STACK_ERROR;
1216                     goto exit;
1217                 }
1218             }
1219             else
1220             {
1221                 stackRet = OC_STACK_ERROR;
1222             }
1223
1224         }
1225         else if (strcmp(doWhat, DELETE_ACTIONSET) == 0)
1226         {
1227             if (FindAndDeleteActionSet(&resource, details) == OC_STACK_OK)
1228             {
1229                 stackRet = OC_STACK_OK;
1230             }
1231             else
1232             {
1233                 stackRet = OC_STACK_ERROR;
1234             }
1235         }
1236
1237         OCRepPayload* payload = OCRepPayloadCreate();
1238
1239         if(!payload)
1240         {
1241             OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
1242             stackRet = OC_STACK_ERROR;
1243         }
1244         else
1245         {
1246             OCEntityHandlerResponse response = { 0 };
1247
1248             if(stackRet == OC_STACK_OK)
1249                 response.ehResult = OC_EH_OK;
1250             else
1251                 response.ehResult = OC_EH_ERROR;
1252
1253             // Format the response.  Note this requires some info about the request
1254             response.requestHandle = ehRequest->requestHandle;
1255             response.resourceHandle = ehRequest->resource;
1256             response.payload = (OCPayload*) payload;
1257             response.numSendVendorSpecificHeaderOptions = 0;
1258             memset(response.sendVendorSpecificHeaderOptions, 0,
1259                     sizeof response.sendVendorSpecificHeaderOptions);
1260             memset(response.resourceUri, 0, sizeof response. resourceUri);
1261             // Indicate that response is NOT in a persistent buffer
1262             response.persistentBufferFlag = 0;
1263             response.ehResult = (stackRet == OC_STACK_OK)?OC_EH_OK:OC_EH_ERROR;
1264
1265             // Send the response
1266             if (OCDoResponse(&response) != OC_STACK_OK)
1267             {
1268                 OIC_LOG(ERROR, TAG, "Error sending response");
1269                 stackRet = OC_STACK_ERROR;
1270             }
1271         }
1272     }
1273     else if (method == OC_REST_POST)
1274     {
1275         OCActionSet *actionset = NULL;
1276
1277         OCRepPayload* payload = OCRepPayloadCreate();
1278         OCRepPayloadSetUri(payload, resource->uri);
1279
1280         if ((strcmp(doWhat, DO_ACTION) == 0)
1281                 || (strcmp(doWhat, "DoScheduledAction") == 0))
1282         {
1283             char *pActionsetName = NULL;
1284             long int delay = -1;
1285
1286             if (strcmp(doWhat, "DoScheduledAction") == 0)
1287             {
1288                 stackRet = ExtractActionSetNameAndDelaytime(details,
1289                         &pActionsetName, &delay);
1290
1291                 OCFREE(details)
1292                 details = pActionsetName;
1293             }
1294             else
1295             {
1296                 stackRet = OC_STACK_OK;
1297             }
1298
1299             if (stackRet == OC_STACK_OK)
1300             {
1301                 if (GetActionSet(details, resource->actionsetHead,
1302                         &actionset) != OC_STACK_OK)
1303                 {
1304                     OIC_LOG(INFO, TAG, "ERROR");
1305                     stackRet = OC_STACK_ERROR;
1306                 }
1307
1308                 if (actionset == NULL)
1309                 {
1310                     OIC_LOG(INFO, TAG, "Cannot Find ActionSet");
1311                     stackRet = OC_STACK_ERROR;
1312                 }
1313                 else
1314                 {
1315                     OIC_LOG(INFO, TAG, "Group Action[POST].");
1316                     if (actionset->type == NONE)
1317                     {
1318                         OIC_LOG_V(INFO, TAG, "Execute ActionSet : %s",
1319                                 actionset->actionsetName);
1320                         unsigned int num = GetNumOfTargetResource(
1321                                 actionset->head);
1322
1323                         ((OCServerRequest *) ehRequest->requestHandle)->ehResponseHandler =
1324                                 HandleAggregateResponse;
1325                         ((OCServerRequest *) ehRequest->requestHandle)->numResponses =
1326                                 num + 1;
1327
1328                         DoAction(resource, actionset,
1329                                 (OCServerRequest*) ehRequest->requestHandle);
1330                         stackRet = OC_STACK_OK;
1331                     }
1332                     else
1333                     {
1334                         OIC_LOG_V(INFO, TAG, "Execute Scheduled ActionSet : %s",
1335                                 actionset->actionsetName);
1336
1337                         delay =
1338                                 (delay == -1 ? actionset->timesteps : delay);
1339
1340                         ScheduledResourceInfo *schedule;
1341                         schedule = (ScheduledResourceInfo *) OICMalloc(
1342                                 sizeof(ScheduledResourceInfo));
1343
1344                         if (schedule)
1345                         {
1346                             OIC_LOG(INFO, TAG, "Building New Call Info.");
1347                             memset(schedule, 0,
1348                                     sizeof(ScheduledResourceInfo));
1349                             MUTEX_LOCK(&lock);
1350                             schedule->resource = resource;
1351                             schedule->actionset = actionset;
1352                             schedule->ehRequest =
1353                                     (OCServerRequest*) ehRequest->requestHandle;
1354                             MUTEX_UNLOCK(&lock);
1355                             if (delay > 0)
1356                             {
1357                                 OIC_LOG_V(INFO, TAG, "delay_time is %ld seconds.",
1358                                         actionset->timesteps);
1359                                 MUTEX_LOCK(&lock);
1360                                 schedule->time = registerTimer(delay,
1361                                         &schedule->timer_id,
1362                                         &DoScheduledGroupAction);
1363                                 MUTEX_UNLOCK(&lock);
1364                                 AddScheduledResource(&scheduleResourceList,
1365                                         schedule);
1366                                 stackRet = OC_STACK_OK;
1367                             }
1368                             else
1369                             {
1370                                 stackRet = OC_STACK_ERROR;
1371                             }
1372                         }
1373                     }
1374                 }
1375             }
1376         }
1377         else if (strcmp(doWhat, "CancelAction") == 0)
1378         {
1379             ScheduledResourceInfo *info =
1380                     GetScheduledResourceByActionSetName(scheduleResourceList, details);
1381
1382             if(info != NULL)
1383             {
1384                 unregisterTimer(info->timer_id);
1385
1386                 RemoveScheduledResource(&scheduleResourceList, info);
1387                 stackRet = OC_STACK_OK;
1388             }
1389             else
1390             {
1391                 stackRet = OC_STACK_ERROR;
1392             }
1393         }
1394
1395         else if (strcmp(doWhat, GET_ACTIONSET) == 0)
1396         {
1397             char *plainText = NULL;
1398             OCActionSet *actionset = NULL;
1399
1400             GetActionSet(details, resource->actionsetHead, &actionset);
1401             if (actionset != NULL)
1402             {
1403                 BuildStringFromActionSet(actionset, &plainText);
1404
1405                 if (plainText != NULL)
1406                 {
1407                     OCRepPayloadSetPropString(payload, ACTIONSET, plainText);
1408                 }
1409                 OICFree(plainText);
1410                 stackRet = OC_STACK_OK;
1411             }
1412         }
1413
1414         if(!payload)
1415         {
1416             OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
1417             stackRet = OC_STACK_ERROR;
1418         }
1419         else
1420         {
1421             OCEntityHandlerResponse response = { 0 };
1422             if(stackRet == OC_STACK_OK)
1423                 response.ehResult = OC_EH_OK;
1424             else
1425                 response.ehResult = OC_EH_ERROR;
1426
1427             // Format the response.  Note this requires some info about the request
1428             response.requestHandle = ehRequest->requestHandle;
1429             response.resourceHandle = ehRequest->resource;
1430             response.payload = (OCPayload*) payload;
1431             response.numSendVendorSpecificHeaderOptions = 0;
1432             memset(response.sendVendorSpecificHeaderOptions, 0,
1433                     sizeof response.sendVendorSpecificHeaderOptions);
1434             memset(response.resourceUri, 0, sizeof response.resourceUri);
1435             // Indicate that response is NOT in a persistent buffer
1436             response.persistentBufferFlag = 0;
1437             response.ehResult = (stackRet == OC_STACK_OK)?OC_EH_OK:OC_EH_ERROR;
1438
1439             // Send the response
1440             if (OCDoResponse(&response) != OC_STACK_OK)
1441             {
1442                 OIC_LOG(ERROR, TAG, "Error sending response");
1443                 stackRet = OC_STACK_ERROR;
1444             }
1445         }
1446     }
1447
1448 exit:
1449
1450     OCFREE(doWhat)
1451     OCFREE(details)
1452
1453     return stackRet;
1454 }