Merge branch 'master' into windows-port
[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 <string.h>
24
25 #include "oicgroup.h"
26 #include "cJSON.h"
27 #include "cbor.h"
28 #include "ocpayload.h"
29 #include "oic_malloc.h"
30 #include "oic_string.h"
31 #include "occollection.h"
32 #include "logger.h"
33 #include "timer.h"
34
35 #include "platform_features.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     if(*actionset == NULL)
440         return;
441
442     OCAction* pointer = (*actionset)->head;
443     OCAction* pDel = NULL;
444
445     while (pointer)
446     {
447         pDel = pointer;
448         pointer = pointer->next;
449
450         DeleteAction(&pDel);
451     }
452     //    (*actionset)->head = NULL;
453     OCFREE((*actionset)->actionsetName)
454     OCFREE(*actionset)
455 }
456
457 OCStackResult FindAndDeleteActionSet(OCResource **resource,
458         const char * actionsetName)
459 {
460     if (*resource != NULL)
461     {
462         OCActionSet *pointer = NULL;
463         OCActionSet *pDel = NULL;
464
465         pointer = (*resource)->actionsetHead;
466
467         if (pointer == NULL)
468         {
469             return OC_STACK_ERROR;
470         }
471         else
472         {
473             if (strcmp(pointer->actionsetName, actionsetName) == 0)
474             {
475                 if (pointer->next != NULL)
476                     (*resource)->actionsetHead = pointer->next;
477                 else
478                     (*resource)->actionsetHead = NULL;
479
480                 DeleteActionSet(&pointer);
481             }
482             else if (pointer->next != NULL)
483             {
484                 while (pointer)
485                 {
486                     if (pointer->next != NULL)
487                     {
488                         if (strcmp(pointer->next->actionsetName, actionsetName)
489                                 == 0)
490                         {
491                             pDel = pointer->next;
492                             pointer->next = pointer->next->next;
493
494                             DeleteActionSet(&pDel);
495                         }
496                     }
497                     pointer = pointer->next;
498                 }
499             }
500
501             return OC_STACK_OK;
502         }
503
504     }
505     return OC_STACK_ERROR;
506 }
507
508 OCStackResult GetActionSet(const char *actionName, OCActionSet *head,
509         OCActionSet** actionset)
510 {
511     OCActionSet *pointer = head;
512
513     while (pointer)
514     {
515         if (strcmp(pointer->actionsetName, actionName) == 0)
516         {
517             *actionset = pointer;
518             return OC_STACK_OK;
519         }
520
521         pointer = pointer->next;
522     }
523
524     return OC_STACK_ERROR;
525
526 }
527
528 OCStackResult ExtractKeyValueFromRequest(OCEntityHandlerRequest *ehRequest,
529                                         char **key, char **value)
530 {
531     OCStackResult result = OC_STACK_OK;
532
533     char *actionSetStr = NULL;
534
535     if( NULL == ehRequest->payload )
536     {
537         result = OC_STACK_ERROR;
538         goto exit;
539     }
540
541     OCRepPayload* input;
542
543     input = (OCRepPayload*)(ehRequest->payload);
544
545     if(OCRepPayloadGetPropString(input, ACTIONSET, &actionSetStr))
546     {
547         *key = OICStrdup(ACTIONSET);
548         VARIFY_POINTER_NULL(*key, result, exit);
549
550         *value = OICStrdup(actionSetStr);
551         VARIFY_POINTER_NULL(*value, result, exit);
552     }
553     else if(OCRepPayloadGetPropString(input, DO_ACTION, &actionSetStr))
554     {
555         *key = OICStrdup(DO_ACTION);
556         VARIFY_POINTER_NULL(*key, result, exit);
557
558         *value = OICStrdup(actionSetStr);
559         VARIFY_POINTER_NULL(*value, result, exit);
560     }
561     else if(OCRepPayloadGetPropString(input, GET_ACTIONSET, &actionSetStr))
562     {
563         *key = OICStrdup(GET_ACTIONSET);
564         VARIFY_POINTER_NULL(*key, result, exit);
565
566         *value = OICStrdup(actionSetStr);
567         VARIFY_POINTER_NULL(*value, result, exit);
568     }
569     else if(OCRepPayloadGetPropString(input, DELETE_ACTIONSET, &actionSetStr))
570     {
571         *key = OICStrdup(DELETE_ACTIONSET);
572         VARIFY_POINTER_NULL(*key, result, exit);
573
574         *value = OICStrdup(actionSetStr);
575         VARIFY_POINTER_NULL(*value, result, exit);
576     }
577     else if(OCRepPayloadGetPropString(input, CANCEL_ACTIONSET, &actionSetStr))
578     {
579         *key = OICStrdup(CANCEL_ACTIONSET);
580         VARIFY_POINTER_NULL(*key, result, exit);
581
582         *value = OICStrdup(actionSetStr);
583         VARIFY_POINTER_NULL(*value, result, exit);
584     }
585     else
586     {
587         result = OC_STACK_ERROR;
588     }
589
590 exit:
591     if (result != OC_STACK_OK)
592     {
593         OCFREE(*key)
594         OCFREE(*value)
595     }
596
597     OCFREE(actionSetStr);
598
599     return result;
600 }
601
602 OCStackResult ExtractActionSetNameAndDelaytime(char *pChar, char **setName,
603         long int *pa)
604 {
605     char *token = NULL, *tokenPtr = NULL;
606     OCStackResult result = OC_STACK_OK;
607
608     token = (char*) strtok_r(pChar, ACTION_DELIMITER, &tokenPtr);
609     VARIFY_POINTER_NULL(token, result, exit)
610
611     *setName = (char *) OICMalloc(strlen(token) + 1);
612     VARIFY_POINTER_NULL(*setName, result, exit)
613     VARIFY_PARAM_NULL(token, result, exit)
614     strncpy(*setName, token, strlen(token) + 1);
615
616     token = strtok_r(NULL, ACTION_DELIMITER, &tokenPtr);
617     VARIFY_POINTER_NULL(pa, result, exit)
618     VARIFY_PARAM_NULL(token, result, exit)
619     *pa = atoi(token);
620
621     return OC_STACK_OK;
622
623 exit:
624     OCFREE(*setName);
625     return result;
626 }
627
628 OCStackResult BuildActionSetFromString(OCActionSet **set, char* actiondesc)
629 {
630     OCStackResult result = OC_STACK_OK;
631
632     char *iterToken = NULL, *iterTokenPtr = NULL;
633     char *descIterToken = NULL, *descIterTokenPtr = NULL;
634     char *attrIterToken = NULL, *attrIterTokenPtr = NULL;
635     char *desc = NULL, *attr = NULL;
636     char *key = NULL, *value = NULL;
637
638     OCAction *action = NULL;
639     OCCapability *capa = NULL;
640
641     OIC_LOG(INFO, TAG, "Build ActionSet Instance.");
642
643     *set = (OCActionSet*) OICMalloc(sizeof(OCActionSet));
644     VARIFY_POINTER_NULL(*set, result, exit)
645
646     iterToken = (char *) strtok_r(actiondesc, ACTION_DELIMITER, &iterTokenPtr);
647     VARIFY_POINTER_NULL(iterToken, result, exit);
648
649     // ActionSet Name
650     memset(*set, 0, sizeof(OCActionSet));
651     (*set)->actionsetName = (char *) OICMalloc(strlen(iterToken) + 1);
652     VARIFY_POINTER_NULL((*set)->actionsetName, result, exit)
653     VARIFY_PARAM_NULL(iterToken, result, exit)
654     strncpy((*set)->actionsetName, iterToken, strlen(iterToken) + 1);
655
656     // Time info. for Scheduled/Recursive Group action.
657     // d is meant Day of the week.
658     // T is meant ActionType.
659     // yyyy-mm-dd hh:mm:ss d
660     iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
661     VARIFY_PARAM_NULL(iterToken, result, exit)
662 #if !defined(WITH_ARDUINO)
663     if( 2 != sscanf(iterToken, "%ld %u", &(*set)->timesteps, &(*set)->type) )
664     {
665         // If the return value should be 2, the number of items in the argument. Otherwise, it fails.
666         goto exit;
667     }
668 #endif
669
670     OIC_LOG_V(INFO, TAG, "ActionSet Name : %s", (*set)->actionsetName);
671
672     iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
673     while (iterToken)
674     {
675         desc = (char *) OICMalloc(strlen(iterToken) + 1);
676         VARIFY_POINTER_NULL(desc, result, exit)
677         VARIFY_PARAM_NULL(desc, result, exit)
678         strncpy(desc, iterToken, strlen(iterToken) + 1);
679         descIterToken = (char *) strtok_r(desc, ATTR_DELIMITER,
680                 &descIterTokenPtr);
681         while (descIterToken)
682         {
683             attr = (char *) OICMalloc(strlen(descIterToken) + 1);
684             VARIFY_POINTER_NULL(attr, result, exit)
685             VARIFY_PARAM_NULL(descIterToken, result, exit)
686             strncpy(attr, descIterToken, strlen(descIterToken) + 1);
687
688             attrIterToken = (char *) strtok_r(attr, ATTR_ASSIGN,
689                     &attrIterTokenPtr);
690             VARIFY_POINTER_NULL(attrIterToken, result, exit);
691
692             key = (char *) OICMalloc(strlen(attrIterToken) + 1);
693             VARIFY_POINTER_NULL(key, result, exit)
694             VARIFY_PARAM_NULL(attrIterToken, result, exit)
695             strncpy(key, attrIterToken, strlen(attrIterToken) + 1);
696
697             attrIterToken = (char *) strtok_r(NULL, ATTR_ASSIGN,
698                     &attrIterTokenPtr);
699             VARIFY_POINTER_NULL(attrIterToken, result, exit);
700             value = (char *) OICMalloc(strlen(attrIterToken) + 1);
701             VARIFY_POINTER_NULL(value, result, exit)
702             VARIFY_PARAM_NULL(attrIterToken, result, exit)
703             strncpy(value, attrIterToken, strlen(attrIterToken) + 1);
704
705             if (strcmp(key, "uri") == 0)
706             {
707                 OIC_LOG(INFO, TAG, "Build OCAction Instance.");
708
709                 action = (OCAction*) OICMalloc(sizeof(OCAction));
710                 VARIFY_POINTER_NULL(action, result, exit)
711                 memset(action, 0, sizeof(OCAction));
712                 action->resourceUri = (char *) OICMalloc(strlen(value) + 1);
713                 VARIFY_POINTER_NULL(action->resourceUri, result, exit)
714                 VARIFY_PARAM_NULL(value, result, exit)
715                 strncpy(action->resourceUri, value, strlen(value) + 1);
716             }
717             else
718             {
719                 if ((key != NULL) && (value != NULL))
720                 {
721                     OIC_LOG(INFO, TAG, "Build OCCapability Instance.");
722
723                     capa = (OCCapability*) OICMalloc(sizeof(OCCapability));
724                     VARIFY_POINTER_NULL(capa, result, exit)
725                     memset(capa, 0, sizeof(OCCapability));
726
727                     capa->capability = (char *) OICMalloc(strlen(key) + 1);
728                     VARIFY_POINTER_NULL(capa->capability, result, exit)
729                     VARIFY_PARAM_NULL(key, result, exit)
730                     strncpy(capa->capability, key, strlen(key) + 1);
731
732                     capa->status = (char *) OICMalloc(strlen(value) + 1);
733                     VARIFY_POINTER_NULL(capa->status, result, exit)
734                     VARIFY_PARAM_NULL(value, result, exit)
735                     strncpy(capa->status, value, strlen(value) + 1);
736
737                     VARIFY_POINTER_NULL(action, result, exit)
738
739                     AddCapability(&action->head, capa);
740                 }
741             }
742
743             OCFREE(key)
744             OCFREE(value)
745             OCFREE(attr)
746
747             descIterToken = (char *) strtok_r(NULL, ATTR_DELIMITER,
748                     &descIterTokenPtr);
749         }
750
751         AddAction(&(*set)->head, action);
752         iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
753         OCFREE(desc);
754     }
755
756     return OC_STACK_OK;
757 exit:
758     OCFREE(attr)
759     OCFREE(desc)
760     OCFREE(capa)
761     OCFREE(action)
762     OCFREE(*set)
763     OCFREE(key)
764     OCFREE(value)
765     OCFREE(attr)
766
767     return result;
768 }
769
770 OCStackResult BuildStringFromActionSet(OCActionSet* actionset, char** desc)
771 {
772     // Can't use the macros here as they are hardcoded to 'exit' and will
773     // result in dereferencing a null pointer.
774     if (!actionset || !desc)
775     {
776         return OC_STACK_INVALID_PARAM;
777     }
778     char temp[1024] = { 0 };
779     size_t remaining = sizeof(temp) - 1;
780     OCStackResult res = OC_STACK_ERROR;
781     char* actionTypeStr = NULL;
782
783     OCAction *action = actionset->head;
784
785     if (remaining >= strlen(actionset->actionsetName) + 1)
786     {
787         strncat(temp, actionset->actionsetName, strlen(actionset->actionsetName));
788         remaining -= strlen(actionset->actionsetName);
789         strncat(temp, ACTION_DELIMITER, strlen(ACTION_DELIMITER));
790         remaining--;
791     }
792     else
793     {
794         res = OC_STACK_ERROR;
795         goto exit;
796     }
797
798     actionTypeStr = (char *)malloc(1024);
799     if(actionTypeStr != NULL)
800     {
801         sprintf(actionTypeStr, "%ld %u", actionset->timesteps, actionset->type);
802         if(remaining >= strlen(actionTypeStr) + strlen(ACTION_DELIMITER) + 1)
803         {
804             strncat(temp, actionTypeStr, strlen(actionTypeStr));
805             remaining -= strlen(actionTypeStr);
806             strncat(temp, ACTION_DELIMITER, strlen(ACTION_DELIMITER));
807             remaining -= strlen(ACTION_DELIMITER);
808             free(actionTypeStr);
809         }
810         else
811         {
812             free(actionTypeStr);
813             res = OC_STACK_ERROR;
814             goto exit;
815         }
816     }
817     else
818     {
819         res = OC_STACK_ERROR;
820         goto exit;
821     }
822
823     while (action != NULL)
824     {
825         if (remaining < (strlen("uri=") + strlen(action->resourceUri) + 1))
826         {
827             res = OC_STACK_ERROR;
828             goto exit;
829         }
830
831         strcat(temp, "uri=");
832         remaining -= strlen("uri=");
833         strcat(temp, action->resourceUri);
834         remaining -= strlen(action->resourceUri);
835         strcat(temp, "|");
836         remaining--;
837
838         OCCapability *capas = action->head;
839         while (capas != NULL)
840         {
841             if (remaining < (strlen(capas->capability)
842                              + 1 + strlen(capas->status)))
843             {
844                 res = OC_STACK_ERROR;
845                 goto exit;
846             }
847
848             strcat(temp, capas->capability);
849             remaining -= strlen(capas->capability);
850             strcat(temp, "=");
851             remaining--;
852             strcat(temp, capas->status);
853             remaining -= strlen(capas->status);
854
855             capas = capas->next;
856             if (capas != NULL)
857             {
858                 if (remaining < 1)
859                 {
860                     res = OC_STACK_ERROR;
861                     goto exit;
862                 }
863                 strcat(temp, "|");
864                 remaining --;
865             }
866         }
867
868         action = action->next;
869         if (action != NULL)
870         {
871             if (remaining < strlen(ACTION_DELIMITER))
872             {
873                 res = OC_STACK_ERROR;
874                 goto exit;
875             }
876             strcat(temp, ACTION_DELIMITER);
877             remaining--;
878         }
879     }
880
881     *desc = OICStrdup(temp);
882     VARIFY_POINTER_NULL(*desc, res, exit);
883
884     return OC_STACK_OK;
885
886 exit:
887     OCFREE(*desc);
888     return res;
889 }
890
891 OCStackApplicationResult ActionSetCB(void* context, OCDoHandle handle,
892         OCClientResponse* clientResponse)
893 {
894     (void)context;
895     (void)clientResponse;
896     OIC_LOG(INFO, TAG, "Entering ActionSetCB");
897
898     ClientRequestInfo *info = GetClientRequestInfo(clientRequstList, handle);
899
900     if (info)
901     {
902         OCEntityHandlerResponse response = { 0 };
903
904         response.ehResult = OC_EH_OK;
905
906         if(NULL == clientResponse->payload)
907         {
908             OIC_LOG(ERROR, TAG, "Error sending response");
909             return OC_STACK_DELETE_TRANSACTION;
910         }
911
912         // Format the response.  Note this requires some info about the request
913         response.requestHandle = info->ehRequest;
914         response.resourceHandle = info->collResource;
915         response.payload = clientResponse->payload;
916         response.numSendVendorSpecificHeaderOptions = 0;
917         memset(response.sendVendorSpecificHeaderOptions, 0,
918                 sizeof response.sendVendorSpecificHeaderOptions);
919         memset(response.resourceUri, 0, sizeof response.resourceUri);
920         // Indicate that response is NOT in a persistent buffer
921         response.persistentBufferFlag = 0;
922
923         // Send the response
924         if (OCDoResponse(&response) != OC_STACK_OK)
925         {
926             OIC_LOG(ERROR, TAG, "Error sending response");
927             return OC_STACK_DELETE_TRANSACTION;
928         }
929
930         RemoveClientRequestInfo(&clientRequstList, info);
931         OCFREE(info)
932     }
933
934     return OC_STACK_KEEP_TRANSACTION;
935 }
936
937 void ActionSetCD(void *context)
938 {
939     (void)context;
940 }
941
942 OCStackResult BuildActionJSON(OCAction* action, unsigned char* bufferPtr,
943         uint16_t *remaining)
944 {
945     OCStackResult ret = OC_STACK_ERROR;
946     cJSON *json;
947     cJSON *body;
948
949     char *jsonStr;
950     uint16_t jsonLen;
951
952     OIC_LOG(INFO, TAG, "Entering BuildActionJSON");
953     json = cJSON_CreateObject();
954
955     cJSON_AddItemToObject(json, "rep", body = cJSON_CreateObject());
956
957     OCCapability* pointerCapa = action->head;
958     while (pointerCapa)
959     {
960         cJSON_AddStringToObject(body, pointerCapa->capability,
961                 pointerCapa->status);
962         pointerCapa = pointerCapa->next;
963     }
964
965     jsonStr = cJSON_PrintUnformatted(json);
966
967     jsonLen = strlen(jsonStr);
968     if (jsonLen < *remaining)
969     {
970         strncat((char*) bufferPtr, jsonStr, jsonLen);
971         *remaining -= jsonLen;
972         bufferPtr += jsonLen;
973         ret = OC_STACK_OK;
974     }
975
976     cJSON_Delete(json);
977     free(jsonStr);
978
979     return ret;
980 }
981
982 OCPayload* BuildActionCBOR(OCAction* action)
983 {
984     OCRepPayload* payload = OCRepPayloadCreate();
985
986     if (!payload)
987     {
988         OIC_LOG(INFO, TAG, "Failed to create put payload object");
989         return NULL;
990     }
991
992     OCCapability* pointerCapa = action->head;
993     while (pointerCapa)
994     {
995         OCRepPayloadSetPropString(payload, pointerCapa->capability, pointerCapa->status);
996         pointerCapa = pointerCapa->next;
997     }
998
999     return (OCPayload*) payload;
1000 }
1001
1002 unsigned int GetNumOfTargetResource(OCAction *actionset)
1003 {
1004     int numOfResource = 0;
1005
1006     OCAction *pointerAction = actionset;
1007
1008     while (pointerAction != NULL)
1009     {
1010         numOfResource++;
1011         pointerAction = pointerAction->next;
1012     }
1013
1014     return numOfResource;
1015 }
1016
1017 OCStackResult SendAction(OCDoHandle *handle, OCServerRequest* requestHandle, const char *targetUri,
1018         OCPayload *payload)
1019 {
1020
1021     OCCallbackData cbData;
1022     cbData.cb = &ActionSetCB;
1023     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
1024     cbData.cd = NULL;
1025
1026     return OCDoResource(handle, OC_REST_PUT, targetUri, &requestHandle->devAddr,
1027                        payload, CT_ADAPTER_IP, OC_NA_QOS, &cbData, NULL, 0);
1028 }
1029
1030 OCStackResult DoAction(OCResource* resource, OCActionSet* actionset,
1031         OCServerRequest* requestHandle)
1032 {
1033     OCStackResult result = OC_STACK_ERROR;
1034
1035     if( NULL == actionset->head)
1036     {
1037         return result;
1038     }
1039
1040     OCAction *pointerAction = actionset->head;
1041
1042     while (pointerAction != NULL)
1043     {
1044         OCPayload* payload;
1045         payload = BuildActionCBOR(pointerAction);
1046
1047         if(payload == NULL)
1048         {
1049             return result;
1050         }
1051
1052         ClientRequestInfo *info = (ClientRequestInfo *) OICMalloc(
1053                 sizeof(ClientRequestInfo));
1054
1055         if( info == NULL )
1056         {
1057             OCFREE(payload);
1058             return OC_STACK_NO_MEMORY;
1059         }
1060
1061         memset(info, 0, sizeof(ClientRequestInfo));
1062
1063         info->collResource = resource;
1064         info->ehRequest = requestHandle;
1065
1066         result = SendAction(&info->required, info->ehRequest, pointerAction->resourceUri,
1067                 payload);
1068
1069         if (result != OC_STACK_OK)
1070         {
1071             OICFree(info);
1072             return result;
1073         }
1074
1075         AddClientRequestInfo(&clientRequstList, info);
1076
1077         pointerAction = pointerAction->next;
1078     }
1079
1080     return result;
1081 }
1082
1083 void DoScheduledGroupAction()
1084 {
1085     OIC_LOG(INFO, TAG, "DoScheduledGroupAction Entering...");
1086     ScheduledResourceInfo* info = GetScheduledResource(scheduleResourceList);
1087
1088     if (info == NULL)
1089     {
1090         OIC_LOG(INFO, TAG, "Target resource is NULL");
1091         goto exit;
1092     }
1093     else if (info->resource == NULL)
1094     {
1095         OIC_LOG(INFO, TAG, "Target resource is NULL");
1096         goto exit;
1097     }
1098     else if (info->actionset == NULL)
1099     {
1100         OIC_LOG(INFO, TAG, "Target ActionSet is NULL");
1101         goto exit;
1102     }
1103     else if (info->ehRequest == NULL)
1104     {
1105         OIC_LOG(INFO, TAG, "Target ActionSet is NULL");
1106         goto exit;
1107     }
1108
1109     MUTEX_LOCK(&lock);
1110
1111     DoAction(info->resource, info->actionset, info->ehRequest);
1112
1113     MUTEX_UNLOCK(&lock);
1114
1115
1116     if (info->actionset->type == RECURSIVE)
1117     {
1118         ScheduledResourceInfo *schedule;
1119         schedule = (ScheduledResourceInfo *) OICMalloc(
1120                 sizeof(ScheduledResourceInfo));
1121
1122         if (schedule)
1123         {
1124             OIC_LOG(INFO, TAG, "Building New Call Info.");
1125             memset(schedule, 0, sizeof(ScheduledResourceInfo));
1126
1127             if (info->actionset->timesteps > 0)
1128             {
1129                 MUTEX_LOCK(&lock);
1130                 schedule->resource = info->resource;
1131                 schedule->actionset = info->actionset;
1132                 schedule->ehRequest = info->ehRequest;
1133
1134                 schedule->time = registerTimer(info->actionset->timesteps,
1135                         &schedule->timer_id,
1136                         &DoScheduledGroupAction);
1137
1138                 OIC_LOG(INFO, TAG, "Reregisteration.");
1139                 MUTEX_UNLOCK(&lock);
1140                 AddScheduledResource(&scheduleResourceList, schedule);
1141             }
1142             else
1143             {
1144                 OICFree(schedule);
1145             }
1146         }
1147     }
1148
1149     RemoveScheduledResource(&scheduleResourceList, info);
1150
1151     exit:
1152
1153     return;
1154 }
1155
1156 OCStackResult BuildCollectionGroupActionCBORResponse(
1157         OCMethod method/*OCEntityHandlerFlag flag*/, OCResource *resource,
1158         OCEntityHandlerRequest *ehRequest)
1159 {
1160     OCStackResult stackRet = OC_STACK_ERROR;
1161
1162     OIC_LOG(INFO, TAG, "Group Action is requested.");
1163
1164     char *doWhat = NULL;
1165     char *details = NULL;
1166
1167 #if defined(_WIN32)
1168     static bool initializedCriticalSection = false;
1169
1170     if(false == initializedCriticalSection) {
1171         /** @todo Find a way to DeleteCriticalSection somewhere. */
1172         InitializeCriticalSection(&lock);
1173         initializedCriticalSection = true;
1174     }
1175 #endif
1176
1177     stackRet = ExtractKeyValueFromRequest(ehRequest, &doWhat, &details);
1178
1179     if(stackRet != OC_STACK_OK)
1180     {
1181         OIC_LOG_V(ERROR, TAG, "ExtractKeyValueFromRequest failed: %d", stackRet);
1182         return stackRet;
1183     }
1184
1185     stackRet = OC_STACK_ERROR;
1186
1187     if (method == OC_REST_PUT)
1188     {
1189         OIC_LOG(INFO, TAG, "Group Action[PUT].");
1190
1191         if (strcmp(doWhat, ACTIONSET) == 0)
1192         {
1193             OCActionSet *actionSet = NULL;
1194             stackRet = BuildActionSetFromString(&actionSet, details);
1195
1196             if(stackRet == OC_STACK_OK)
1197             {
1198                 if (actionSet != NULL)
1199                 {
1200                     stackRet = AddActionSet(&resource->actionsetHead,
1201                             actionSet);
1202                     if (stackRet == OC_STACK_ERROR)
1203                     {
1204                         if(actionSet != NULL)
1205                         {
1206                             DeleteActionSet( &actionSet );
1207                         }
1208                         OIC_LOG(INFO, TAG, "Duplicated ActionSet ");
1209                     }
1210                 }
1211                 else
1212                 {
1213                     stackRet = OC_STACK_ERROR;
1214                     goto exit;
1215                 }
1216             }
1217             else
1218             {
1219                 stackRet = OC_STACK_ERROR;
1220             }
1221
1222         }
1223         else if (strcmp(doWhat, DELETE_ACTIONSET) == 0)
1224         {
1225             if (FindAndDeleteActionSet(&resource, details) == OC_STACK_OK)
1226             {
1227                 stackRet = OC_STACK_OK;
1228             }
1229             else
1230             {
1231                 stackRet = OC_STACK_ERROR;
1232             }
1233         }
1234
1235         OCRepPayload* payload = OCRepPayloadCreate();
1236
1237         if(!payload)
1238         {
1239             OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
1240             stackRet = OC_STACK_ERROR;
1241         }
1242         else
1243         {
1244             OCEntityHandlerResponse response = { 0 };
1245
1246             if(stackRet == OC_STACK_OK)
1247                 response.ehResult = OC_EH_OK;
1248             else
1249                 response.ehResult = OC_EH_ERROR;
1250
1251             // Format the response.  Note this requires some info about the request
1252             response.requestHandle = ehRequest->requestHandle;
1253             response.resourceHandle = ehRequest->resource;
1254             response.payload = (OCPayload*) payload;
1255             response.numSendVendorSpecificHeaderOptions = 0;
1256             memset(response.sendVendorSpecificHeaderOptions, 0,
1257                     sizeof response.sendVendorSpecificHeaderOptions);
1258             memset(response.resourceUri, 0, sizeof response. resourceUri);
1259             // Indicate that response is NOT in a persistent buffer
1260             response.persistentBufferFlag = 0;
1261             response.ehResult = (stackRet == OC_STACK_OK)?OC_EH_OK:OC_EH_ERROR;
1262
1263             // Send the response
1264             if (OCDoResponse(&response) != OC_STACK_OK)
1265             {
1266                 OIC_LOG(ERROR, TAG, "Error sending response");
1267                 stackRet = OC_STACK_ERROR;
1268             }
1269         }
1270     }
1271     else if (method == OC_REST_POST)
1272     {
1273         OCActionSet *actionset = NULL;
1274
1275         OCRepPayload* payload = OCRepPayloadCreate();
1276         OCRepPayloadSetUri(payload, resource->uri);
1277
1278         if ((strcmp(doWhat, DO_ACTION) == 0)
1279                 || (strcmp(doWhat, "DoScheduledAction") == 0))
1280         {
1281             char *pActionsetName = NULL;
1282             long int delay = -1;
1283
1284             if (strcmp(doWhat, "DoScheduledAction") == 0)
1285             {
1286                 stackRet = ExtractActionSetNameAndDelaytime(details,
1287                         &pActionsetName, &delay);
1288
1289                 OCFREE(details)
1290                 details = pActionsetName;
1291             }
1292             else
1293             {
1294                 stackRet = OC_STACK_OK;
1295             }
1296
1297             if (stackRet == OC_STACK_OK)
1298             {
1299                 if (GetActionSet(details, resource->actionsetHead,
1300                         &actionset) != OC_STACK_OK)
1301                 {
1302                     OIC_LOG(INFO, TAG, "ERROR");
1303                     stackRet = OC_STACK_ERROR;
1304                 }
1305
1306                 if (actionset == NULL)
1307                 {
1308                     OIC_LOG(INFO, TAG, "Cannot Find ActionSet");
1309                     stackRet = OC_STACK_ERROR;
1310                 }
1311                 else
1312                 {
1313                     OIC_LOG(INFO, TAG, "Group Action[POST].");
1314                     if (actionset->type == NONE)
1315                     {
1316                         OIC_LOG_V(INFO, TAG, "Execute ActionSet : %s",
1317                                 actionset->actionsetName);
1318                         unsigned int num = GetNumOfTargetResource(
1319                                 actionset->head);
1320
1321                         ((OCServerRequest *) ehRequest->requestHandle)->ehResponseHandler =
1322                                 HandleAggregateResponse;
1323                         ((OCServerRequest *) ehRequest->requestHandle)->numResponses =
1324                                 num + 1;
1325
1326                         DoAction(resource, actionset,
1327                                 (OCServerRequest*) ehRequest->requestHandle);
1328                         stackRet = OC_STACK_OK;
1329                     }
1330                     else
1331                     {
1332                         OIC_LOG_V(INFO, TAG, "Execute Scheduled ActionSet : %s",
1333                                 actionset->actionsetName);
1334
1335                         delay =
1336                                 (delay == -1 ? actionset->timesteps : delay);
1337
1338                         ScheduledResourceInfo *schedule;
1339                         schedule = (ScheduledResourceInfo *) OICMalloc(
1340                                 sizeof(ScheduledResourceInfo));
1341
1342                         if (schedule)
1343                         {
1344                             OIC_LOG(INFO, TAG, "Building New Call Info.");
1345                             memset(schedule, 0,
1346                                     sizeof(ScheduledResourceInfo));
1347                             MUTEX_LOCK(&lock);
1348                             schedule->resource = resource;
1349                             schedule->actionset = actionset;
1350                             schedule->ehRequest =
1351                                     (OCServerRequest*) ehRequest->requestHandle;
1352                             MUTEX_UNLOCK(&lock);
1353                             if (delay > 0)
1354                             {
1355                                 OIC_LOG_V(INFO, TAG, "delay_time is %ld seconds.",
1356                                         actionset->timesteps);
1357                                 MUTEX_LOCK(&lock);
1358                                 schedule->time = registerTimer(delay,
1359                                         &schedule->timer_id,
1360                                         &DoScheduledGroupAction);
1361                                 MUTEX_UNLOCK(&lock);
1362                                 AddScheduledResource(&scheduleResourceList,
1363                                         schedule);
1364                                 stackRet = OC_STACK_OK;
1365                             }
1366                             else
1367                             {
1368                                 stackRet = OC_STACK_ERROR;
1369                             }
1370                         }
1371                     }
1372                 }
1373             }
1374         }
1375         else if (strcmp(doWhat, "CancelAction") == 0)
1376         {
1377             ScheduledResourceInfo *info =
1378                     GetScheduledResourceByActionSetName(scheduleResourceList, details);
1379
1380             if(info != NULL)
1381             {
1382                 unregisterTimer(info->timer_id);
1383
1384                 RemoveScheduledResource(&scheduleResourceList, info);
1385                 stackRet = OC_STACK_OK;
1386             }
1387             else
1388             {
1389                 stackRet = OC_STACK_ERROR;
1390             }
1391         }
1392
1393         else if (strcmp(doWhat, GET_ACTIONSET) == 0)
1394         {
1395             char *plainText = NULL;
1396             OCActionSet *actionset = NULL;
1397
1398             GetActionSet(details, resource->actionsetHead, &actionset);
1399             if (actionset != NULL)
1400             {
1401                 BuildStringFromActionSet(actionset, &plainText);
1402
1403                 if (plainText != NULL)
1404                 {
1405                     OCRepPayloadSetPropString(payload, ACTIONSET, plainText);
1406                 }
1407                 OICFree(plainText);
1408                 stackRet = OC_STACK_OK;
1409             }
1410         }
1411
1412         if(!payload)
1413         {
1414             OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
1415             stackRet = OC_STACK_ERROR;
1416         }
1417         else
1418         {
1419             OCEntityHandlerResponse response = { 0 };
1420             if(stackRet == OC_STACK_OK)
1421                 response.ehResult = OC_EH_OK;
1422             else
1423                 response.ehResult = OC_EH_ERROR;
1424
1425             // Format the response.  Note this requires some info about the request
1426             response.requestHandle = ehRequest->requestHandle;
1427             response.resourceHandle = ehRequest->resource;
1428             response.payload = (OCPayload*) payload;
1429             response.numSendVendorSpecificHeaderOptions = 0;
1430             memset(response.sendVendorSpecificHeaderOptions, 0,
1431                     sizeof response.sendVendorSpecificHeaderOptions);
1432             memset(response.resourceUri, 0, sizeof response.resourceUri);
1433             // Indicate that response is NOT in a persistent buffer
1434             response.persistentBufferFlag = 0;
1435             response.ehResult = (stackRet == OC_STACK_OK)?OC_EH_OK:OC_EH_ERROR;
1436
1437             // Send the response
1438             if (OCDoResponse(&response) != OC_STACK_OK)
1439             {
1440                 OIC_LOG(ERROR, TAG, "Error sending response");
1441                 stackRet = OC_STACK_ERROR;
1442             }
1443         }
1444     }
1445
1446 exit:
1447
1448     OCFREE(doWhat)
1449     OCFREE(details)
1450
1451     return stackRet;
1452 }