126 ret = cmd_delete_conflicts(args); |
126 ret = cmd_delete_conflicts(args); |
127 } else if(!strcmp(cmd, "trash-info")) { |
127 } else if(!strcmp(cmd, "trash-info")) { |
128 ret = cmd_trash_info(args); |
128 ret = cmd_trash_info(args); |
129 } else if(!strcmp(cmd, "empty-trash")) { |
129 } else if(!strcmp(cmd, "empty-trash")) { |
130 ret = cmd_empty_trash(args); |
130 ret = cmd_empty_trash(args); |
|
131 } else if(!strcmp(cmd, "add-tag")) { |
|
132 ret = cmd_add_tag(args); |
|
133 } else if(!strcmp(cmd, "remove-tag")) { |
|
134 ret = cmd_remove_tag(args); |
|
135 } else if(!strcmp(cmd, "update-tags")) { |
|
136 ret = cmd_update_tags(args); |
131 } else if(!strcmp(cmd, "add-dir") |
137 } else if(!strcmp(cmd, "add-dir") |
132 || !strcmp(cmd, "add-directory")) { |
138 || !strcmp(cmd, "add-directory")) { |
133 ret = cmd_add_directory(args); |
139 ret = cmd_add_directory(args); |
134 } else if(!strcmp(cmd, "list-dirs") |
140 } else if(!strcmp(cmd, "list-dirs") |
135 || !strcmp(cmd, "list-directories")) { |
141 || !strcmp(cmd, "list-directories")) { |
163 fprintf(stderr, " push [-cld] <directory>\n"); |
169 fprintf(stderr, " push [-cld] <directory>\n"); |
164 fprintf(stderr, " archive [-cld] <directory>\n"); |
170 fprintf(stderr, " archive [-cld] <directory>\n"); |
165 fprintf(stderr, " resolve-conflicts <directory>\n"); |
171 fprintf(stderr, " resolve-conflicts <directory>\n"); |
166 fprintf(stderr, " delete-conflicts <directory>\n"); |
172 fprintf(stderr, " delete-conflicts <directory>\n"); |
167 fprintf(stderr, " trash-info <directory>\n"); |
173 fprintf(stderr, " trash-info <directory>\n"); |
168 fprintf(stderr, " empty-trash <directory>\n\n"); |
174 fprintf(stderr, " empty-trash <directory>\n"); |
|
175 fprintf(stderr, " add-tag [-s <syncdir>] <file> <tag>\n"); |
|
176 fprintf(stderr, " remove-tag [-s <syncdir>] <file> <tag>\n"); |
|
177 fprintf(stderr, " update-tags [-s <syncdir>] <file> [tags]\n\n"); |
169 |
178 |
170 fprintf(stderr, "Options:\n"); |
179 fprintf(stderr, "Options:\n"); |
171 fprintf(stderr, " -c Disable conflict detection\n"); |
180 fprintf(stderr, " -c Disable conflict detection\n"); |
172 fprintf(stderr, " -l Lock the repository before access\n"); |
181 fprintf(stderr, " -l Lock the repository before access\n"); |
173 fprintf(stderr, " -d Don't lock the repository\n"); |
182 fprintf(stderr, " -d Don't lock the repository\n"); |
2039 } |
2066 } |
2040 closedir(dir); |
2067 closedir(dir); |
2041 |
2068 |
2042 return 0; |
2069 return 0; |
2043 } |
2070 } |
|
2071 |
|
2072 #define CMD_TAG_ADD 0 |
|
2073 #define CMD_TAG_REMOVE 1 |
|
2074 #define CMD_TAG_UPDATE 2 |
|
2075 int cmd_add_tag(CmdArgs *args) { |
|
2076 if(args->argc != 2) { |
|
2077 fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many"); |
|
2078 return -1; |
|
2079 } |
|
2080 return cmd_tagopt(args, CMD_TAG_ADD); |
|
2081 } |
|
2082 |
|
2083 int cmd_remove_tag(CmdArgs *args) { |
|
2084 if(args->argc != 2) { |
|
2085 fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many"); |
|
2086 return -1; |
|
2087 } |
|
2088 return cmd_tagopt(args, CMD_TAG_REMOVE); |
|
2089 } |
|
2090 |
|
2091 int cmd_update_tags(CmdArgs *args) { |
|
2092 if(args->argc < 1 || args->argc > 2) { |
|
2093 fprintf(stderr, "Too %s arguments\n", args->argc < 1 ? "few" : "many"); |
|
2094 return -1; |
|
2095 } |
|
2096 return cmd_tagopt(args, CMD_TAG_UPDATE); |
|
2097 } |
|
2098 |
|
2099 int cmd_tagopt(CmdArgs *args, int cmd) { |
|
2100 SyncFile file; |
|
2101 int ret = 0; |
|
2102 char *path = args->argv[0]; |
|
2103 |
|
2104 int err = sync_get_file(args, path, NULL, &file); |
|
2105 if(err) { |
|
2106 fprintf(stderr, "err: %d\n", err); // TODO: print nice err msg |
|
2107 return -1; |
|
2108 } |
|
2109 |
|
2110 if(!file.dir->tagconfig) { |
|
2111 fprintf(stderr, "Tags are not supported for this sync directory\n"); |
|
2112 return -1; |
|
2113 } |
|
2114 |
|
2115 SyncDatabase *db = load_db(file.dir->database); |
|
2116 if(!db) { |
|
2117 fprintf(stderr, "Cannot load sync directory database\n"); |
|
2118 return -1; |
|
2119 } |
|
2120 |
|
2121 LocalResource *localres = ucx_map_cstr_get(db->resources, file.path); |
|
2122 UcxList *tags = NULL; |
|
2123 DavBool store_tags = FALSE; |
|
2124 |
|
2125 if(cmd == CMD_TAG_ADD || cmd == CMD_TAG_REMOVE) { |
|
2126 char *tag = args->argv[1]; |
|
2127 char *tagcolor = NULL; // TODO: get color |
|
2128 |
|
2129 tags = sync_get_file_tags(file.dir, localres, NULL); |
|
2130 UcxList *x = NULL; |
|
2131 UCX_FOREACH(elm, tags) { |
|
2132 DavTag *t = elm->data; |
|
2133 if(!strcmp(t->name, tag)) { |
|
2134 x = elm; |
|
2135 break; |
|
2136 } |
|
2137 } |
|
2138 |
|
2139 if(cmd == CMD_TAG_ADD) { |
|
2140 if(!x) { |
|
2141 DavTag *newtag = malloc(sizeof(DavTag)); |
|
2142 newtag->name = tag; |
|
2143 newtag->color = tagcolor; |
|
2144 tags = ucx_list_append(tags, newtag); |
|
2145 store_tags = TRUE; |
|
2146 } |
|
2147 } else { |
|
2148 if(tags) { |
|
2149 tags = ucx_list_remove(tags, x); |
|
2150 } |
|
2151 store_tags = TRUE; |
|
2152 } |
|
2153 } else { |
|
2154 if(args->argc == 2) { |
|
2155 char *tags_str = args->argv[1]; |
|
2156 tags = parse_csv_taglist(tags_str, strlen(tags_str)); |
|
2157 // TODO: read from stdin if tags_str is "-" |
|
2158 } |
|
2159 } |
|
2160 |
|
2161 if(store_tags) { |
|
2162 if(sync_store_tags_local(file.dir, NULL, path, tags)) { |
|
2163 fprintf(stderr, "Cannot store tags\n"); |
|
2164 } |
|
2165 if(localres) { |
|
2166 localres->tags_updated = TRUE; |
|
2167 } |
|
2168 } |
|
2169 |
|
2170 // store db |
|
2171 if(store_db(db, file.dir->database)) { |
|
2172 fprintf(stderr, "Cannot store sync db\n"); |
|
2173 ret = -2; |
|
2174 } |
|
2175 |
|
2176 free(file.path); |
|
2177 return ret; |
|
2178 } |
|
2179 |
|
2180 static int isfileindir(SyncDirectory *dir, const char *path, SyncFile *f) { |
|
2181 char *fullpath; |
|
2182 if(path[0] != '/') { |
|
2183 size_t wdlen = 1024; |
|
2184 char *wd = malloc(1024); |
|
2185 while(!getcwd(wd, wdlen)) { |
|
2186 if(errno == ERANGE) { |
|
2187 wdlen *= 2; |
|
2188 wd = realloc(wd, wdlen); |
|
2189 } else { |
|
2190 free(wd); |
|
2191 return 0; |
|
2192 } |
|
2193 } |
|
2194 |
|
2195 fullpath = util_concat_path(wd, path); |
|
2196 } else { |
|
2197 fullpath = strdup(path); |
|
2198 } |
|
2199 |
|
2200 // TODO: normalize path |
|
2201 |
|
2202 if(!sstrprefix(sstr((char*)fullpath), sstr(dir->path))) { |
|
2203 free(fullpath); |
|
2204 return 0; |
|
2205 } |
|
2206 |
|
2207 // TODO: check filter |
|
2208 |
|
2209 f->dir = dir; |
|
2210 f->path = util_concat_path("/", fullpath + strlen(dir->path)); |
|
2211 |
|
2212 free(fullpath); |
|
2213 return 1; |
|
2214 } |
|
2215 |
|
2216 int sync_get_file(CmdArgs *args, const char *path, const char *dir, SyncFile *f) { |
|
2217 struct stat s; |
|
2218 if(stat(path, &s)) { |
|
2219 switch(errno) { |
|
2220 case EACCES: return 2; |
|
2221 case ENOENT: return 1; |
|
2222 default: return 3; |
|
2223 } |
|
2224 } |
|
2225 |
|
2226 char *sdir = cmd_getoption(args, "syncdir"); |
|
2227 |
|
2228 if(sdir) { |
|
2229 SyncDirectory *dir = scfg_get_dir(sdir); |
|
2230 if(!dir) { |
|
2231 return 6; |
|
2232 } |
|
2233 if(!isfileindir(dir, path, f)) { |
|
2234 return 4; |
|
2235 } |
|
2236 } else { |
|
2237 SyncDirectory *target = NULL; |
|
2238 |
|
2239 UcxMapIterator i = scfg_directory_iterator(); |
|
2240 UcxKey k; |
|
2241 SyncDirectory *dir; |
|
2242 UCX_MAP_FOREACH(key, dir, i) { |
|
2243 if(isfileindir(dir, path, f)) { |
|
2244 if(target) { |
|
2245 return 5; |
|
2246 } else { |
|
2247 target = dir; |
|
2248 } |
|
2249 } |
|
2250 } |
|
2251 |
|
2252 if(!target) { |
|
2253 return 4; |
|
2254 } |
|
2255 } |
|
2256 |
|
2257 return 0; |
|
2258 } |
|
2259 |
2044 |
2260 |
2045 int cmd_add_directory(CmdArgs *args) { |
2261 int cmd_add_directory(CmdArgs *args) { |
2046 if(!get_repositories()) { |
2262 if(!get_repositories()) { |
2047 fprintf(stderr, "No repositories available. Run 'dav add-repository' first.\n"); |
2263 fprintf(stderr, "No repositories available. Run 'dav add-repository' first.\n"); |
2048 fprintf(stderr, "Abort\n"); |
2264 fprintf(stderr, "Abort\n"); |