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