desktop.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. package main
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "io/ioutil"
  6. "log"
  7. "net/http"
  8. "os"
  9. "path/filepath"
  10. "strconv"
  11. "strings"
  12. fs "imuslab.com/arozos/mod/filesystem"
  13. "imuslab.com/arozos/mod/filesystem/arozfs"
  14. "imuslab.com/arozos/mod/filesystem/shortcut"
  15. module "imuslab.com/arozos/mod/modules"
  16. prout "imuslab.com/arozos/mod/prouter"
  17. "imuslab.com/arozos/mod/utils"
  18. )
  19. //Desktop script initiation
  20. func DesktopInit() {
  21. systemWideLogger.PrintAndLog("Desktop", "Starting Desktop Services", nil)
  22. router := prout.NewModuleRouter(prout.RouterOption{
  23. ModuleName: "Desktop",
  24. AdminOnly: false,
  25. UserHandler: userHandler,
  26. DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
  27. utils.SendErrorResponse(w, "Permission Denied")
  28. },
  29. })
  30. //Register all the required API
  31. router.HandleFunc("/system/desktop/listDesktop", desktop_listFiles)
  32. router.HandleFunc("/system/desktop/theme", desktop_theme_handler)
  33. router.HandleFunc("/system/desktop/files", desktop_fileLocation_handler)
  34. router.HandleFunc("/system/desktop/host", desktop_hostdetailHandler)
  35. router.HandleFunc("/system/desktop/user", desktop_handleUserInfo)
  36. router.HandleFunc("/system/desktop/preference", desktop_preference_handler)
  37. router.HandleFunc("/system/desktop/createShortcut", desktop_shortcutHandler)
  38. //API related to desktop based operations
  39. router.HandleFunc("/system/desktop/opr/renameShortcut", desktop_handleShortcutRename)
  40. //Initialize desktop database
  41. err := sysdb.NewTable("desktop")
  42. if err != nil {
  43. log.Println("Unable to create database table for Desktop. Please validation your installation.")
  44. log.Fatal(err)
  45. os.Exit(1)
  46. }
  47. //Register Desktop Module
  48. moduleHandler.RegisterModule(module.ModuleInfo{
  49. Name: "Desktop",
  50. Desc: "The Web Desktop experience for everyone",
  51. Group: "Interface Module",
  52. IconPath: "img/desktop/desktop.png",
  53. Version: internal_version,
  54. StartDir: "",
  55. SupportFW: false,
  56. LaunchFWDir: "",
  57. SupportEmb: false,
  58. })
  59. }
  60. /*
  61. FUNCTIONS RELATED TO PARSING DESKTOP FILE ICONS
  62. The functions in this section handle file listing and its icon locations.
  63. */
  64. func desktop_initUserFolderStructure(username string) {
  65. //Call to filesystem for creating user file struture at root dir
  66. userinfo, _ := userHandler.GetUserInfoFromUsername(username)
  67. homedir, err := userinfo.GetHomeDirectory()
  68. if err != nil {
  69. systemWideLogger.PrintAndLog("Desktop", "Unable to initiate user desktop folder", err)
  70. return
  71. }
  72. if !fs.FileExists(filepath.Join(homedir, "Desktop")) {
  73. //Desktop directory not exists. Create one and copy a template desktop
  74. os.MkdirAll(homedir+"Desktop", 0755)
  75. templateFolder := "./system/desktop/template/"
  76. if fs.FileExists(templateFolder) {
  77. templateFiles, _ := filepath.Glob(templateFolder + "*")
  78. for _, tfile := range templateFiles {
  79. input, _ := ioutil.ReadFile(tfile)
  80. ioutil.WriteFile(homedir+"Desktop/"+filepath.Base(tfile), input, 0755)
  81. }
  82. }
  83. }
  84. }
  85. //Return the information about the host
  86. func desktop_hostdetailHandler(w http.ResponseWriter, r *http.Request) {
  87. type returnStruct struct {
  88. Hostname string
  89. DeviceUUID string
  90. BuildVersion string
  91. InternalVersion string
  92. DeviceVendor string
  93. DeviceModel string
  94. VendorIcon string
  95. }
  96. jsonString, _ := json.Marshal(returnStruct{
  97. Hostname: *host_name,
  98. DeviceUUID: deviceUUID,
  99. BuildVersion: build_version,
  100. InternalVersion: internal_version,
  101. DeviceVendor: deviceVendor,
  102. DeviceModel: deviceModel,
  103. VendorIcon: iconVendor,
  104. })
  105. utils.SendJSONResponse(w, string(jsonString))
  106. }
  107. func desktop_handleShortcutRename(w http.ResponseWriter, r *http.Request) {
  108. //Check if the user directory already exists
  109. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  110. if err != nil {
  111. utils.SendErrorResponse(w, "User not logged in")
  112. return
  113. }
  114. //Get the shortcut file that is renaming
  115. target, err := utils.Mv(r, "src", false)
  116. if err != nil {
  117. utils.SendErrorResponse(w, "Invalid shortcut file path given")
  118. return
  119. }
  120. //Get the new name
  121. new, err := utils.Mv(r, "new", false)
  122. if err != nil {
  123. utils.SendErrorResponse(w, "Invalid new name given")
  124. return
  125. }
  126. fsh, subpath, _ := GetFSHandlerSubpathFromVpath(target)
  127. fshAbs := fsh.FileSystemAbstraction
  128. //Check if the file actually exists and it is on desktop
  129. rpath, err := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
  130. if err != nil {
  131. utils.SendErrorResponse(w, err.Error())
  132. return
  133. }
  134. if target[:14] != "user:/Desktop/" {
  135. utils.SendErrorResponse(w, "Shortcut not on desktop")
  136. return
  137. }
  138. if !fshAbs.FileExists(rpath) {
  139. utils.SendErrorResponse(w, "File not exists")
  140. return
  141. }
  142. //OK. Change the name of the shortcut
  143. originalShortcut, err := fshAbs.ReadFile(rpath)
  144. if err != nil {
  145. utils.SendErrorResponse(w, "Shortcut file read failed")
  146. return
  147. }
  148. lines := strings.Split(string(originalShortcut), "\n")
  149. if len(lines) < 4 {
  150. //Invalid shortcut properties
  151. utils.SendErrorResponse(w, "Invalid shortcut file")
  152. return
  153. }
  154. //Change the 2nd line to the new name
  155. lines[1] = new
  156. newShortcutContent := strings.Join(lines, "\n")
  157. err = fshAbs.WriteFile(rpath, []byte(newShortcutContent), 0755)
  158. if err != nil {
  159. utils.SendErrorResponse(w, err.Error())
  160. return
  161. }
  162. utils.SendOK(w)
  163. }
  164. func desktop_listFiles(w http.ResponseWriter, r *http.Request) {
  165. //Check if the user directory already exists
  166. userinfo, _ := userHandler.GetUserInfoFromRequest(w, r)
  167. username := userinfo.Username
  168. //Initiate the user folder structure. Do nothing if the structure already exists.
  169. desktop_initUserFolderStructure(username)
  170. //List all files inside the user desktop directory
  171. fsh, subpath, err := GetFSHandlerSubpathFromVpath("user:/Desktop/")
  172. if err != nil {
  173. utils.SendErrorResponse(w, "Desktop file load failed")
  174. return
  175. }
  176. fshAbs := fsh.FileSystemAbstraction
  177. userDesktopRealpath, _ := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
  178. files, err := fshAbs.Glob(userDesktopRealpath + "/*")
  179. if err != nil {
  180. utils.SendErrorResponse(w, "Desktop file load failed")
  181. return
  182. }
  183. //Desktop object structure
  184. type desktopObject struct {
  185. Filepath string
  186. Filename string
  187. Ext string
  188. IsDir bool
  189. IsEmptyDir bool
  190. IsShortcut bool
  191. IsShared bool
  192. ShortcutImage string
  193. ShortcutType string
  194. ShortcutName string
  195. ShortcutPath string
  196. IconX int
  197. IconY int
  198. }
  199. var desktopFiles []desktopObject
  200. for _, this := range files {
  201. //Always use linux convension for directory seperator
  202. if filepath.Base(this)[:1] == "." {
  203. //Skipping hidden files
  204. continue
  205. }
  206. this = filepath.ToSlash(this)
  207. thisFileObject := new(desktopObject)
  208. thisFileObject.Filepath, _ = fshAbs.RealPathToVirtualPath(this, userinfo.Username)
  209. thisFileObject.Filename = filepath.Base(this)
  210. thisFileObject.Ext = filepath.Ext(this)
  211. thisFileObject.IsDir = fshAbs.IsDir(this)
  212. if thisFileObject.IsDir {
  213. //Check if this dir is empty
  214. filesInFolder, _ := fshAbs.Glob(filepath.ToSlash(filepath.Clean(this)) + "/*")
  215. fc := 0
  216. for _, f := range filesInFolder {
  217. if filepath.Base(f)[:1] != "." {
  218. fc++
  219. }
  220. }
  221. if fc > 0 {
  222. thisFileObject.IsEmptyDir = false
  223. } else {
  224. thisFileObject.IsEmptyDir = true
  225. }
  226. } else {
  227. //File object. Default true
  228. thisFileObject.IsEmptyDir = true
  229. }
  230. //Check if the file is a shortcut
  231. isShortcut := false
  232. if filepath.Ext(this) == ".shortcut" {
  233. isShortcut = true
  234. shortcutInfo, _ := fshAbs.ReadFile(this)
  235. infoSegments := strings.Split(strings.ReplaceAll(string(shortcutInfo), "\r\n", "\n"), "\n")
  236. if len(infoSegments) < 4 {
  237. thisFileObject.ShortcutType = "invalid"
  238. } else {
  239. thisFileObject.ShortcutType = infoSegments[0]
  240. thisFileObject.ShortcutName = infoSegments[1]
  241. thisFileObject.ShortcutPath = infoSegments[2]
  242. thisFileObject.ShortcutImage = infoSegments[3]
  243. }
  244. }
  245. thisFileObject.IsShortcut = isShortcut
  246. //Check if this file is shared
  247. thisFileObject.IsShared = shareManager.FileIsShared(userinfo, this)
  248. //Check the file location
  249. username, _ := authAgent.GetUserName(w, r)
  250. x, y, _ := getDesktopLocatioFromPath(thisFileObject.Filename, username)
  251. //This file already have a location on desktop
  252. thisFileObject.IconX = x
  253. thisFileObject.IconY = y
  254. desktopFiles = append(desktopFiles, *thisFileObject)
  255. }
  256. //Convert the struct to json string
  257. jsonString, _ := json.Marshal(desktopFiles)
  258. utils.SendJSONResponse(w, string(jsonString))
  259. }
  260. //functions to handle desktop icon locations. Location is directly written into the center db.
  261. func getDesktopLocatioFromPath(filename string, username string) (int, int, error) {
  262. //As path include username, there is no different if there are username in the key
  263. locationdata := ""
  264. err := sysdb.Read("desktop", username+"/filelocation/"+filename, &locationdata)
  265. if err != nil {
  266. //The file location is not set. Return error
  267. return -1, -1, errors.New("This file do not have a location registry")
  268. }
  269. type iconLocation struct {
  270. X int
  271. Y int
  272. }
  273. thisFileLocation := iconLocation{
  274. X: -1,
  275. Y: -1,
  276. }
  277. //Start parsing the from the json data
  278. json.Unmarshal([]byte(locationdata), &thisFileLocation)
  279. return thisFileLocation.X, thisFileLocation.Y, nil
  280. }
  281. //Set the icon location of a given filepath
  282. func setDesktopLocationFromPath(filename string, username string, x int, y int) error {
  283. //You cannot directly set path of others people's deskop. Hence, fullpath needed to be parsed from auth username
  284. userinfo, _ := userHandler.GetUserInfoFromUsername(username)
  285. fsh, subpath, _ := GetFSHandlerSubpathFromVpath("user:/Desktop/")
  286. fshAbs := fsh.FileSystemAbstraction
  287. desktoppath, _ := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
  288. path := filepath.Join(desktoppath, filename)
  289. type iconLocation struct {
  290. X int
  291. Y int
  292. }
  293. newLocation := new(iconLocation)
  294. newLocation.X = x
  295. newLocation.Y = y
  296. //Check if the file exits
  297. if !fshAbs.FileExists(path) {
  298. return errors.New("Given filename not exists.")
  299. }
  300. //Parse the location to json
  301. jsonstring, err := json.Marshal(newLocation)
  302. if err != nil {
  303. log.Println("[Desktop] Unable to parse new file location on desktop for file: " + path)
  304. return err
  305. }
  306. //systemWideLogger.PrintAndLog(key,string(jsonstring),nil)
  307. //Write result to database
  308. sysdb.Write("desktop", username+"/filelocation/"+filename, string(jsonstring))
  309. return nil
  310. }
  311. func delDesktopLocationFromPath(filename string, username string) {
  312. //Delete a file icon location from db
  313. sysdb.Delete("desktop", username+"/filelocation/"+filename)
  314. }
  315. //Return the user information to the client
  316. func desktop_handleUserInfo(w http.ResponseWriter, r *http.Request) {
  317. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  318. if err != nil {
  319. utils.SendErrorResponse(w, err.Error())
  320. return
  321. }
  322. nic, _ := utils.Mv(r, "noicon", true)
  323. noicon := (nic == "true")
  324. type returnStruct struct {
  325. Username string
  326. UserIcon string
  327. UserGroups []string
  328. IsAdmin bool
  329. StorageQuotaTotal int64
  330. StorageQuotaLeft int64
  331. }
  332. //Calculate the storage quota left
  333. remainingQuota := userinfo.StorageQuota.TotalStorageQuota - userinfo.StorageQuota.UsedStorageQuota
  334. if userinfo.StorageQuota.TotalStorageQuota == -1 {
  335. remainingQuota = -1
  336. }
  337. //Get the list of user permission group names
  338. pgs := []string{}
  339. for _, pg := range userinfo.GetUserPermissionGroup() {
  340. pgs = append(pgs, pg.Name)
  341. }
  342. rs := returnStruct{
  343. Username: userinfo.Username,
  344. UserIcon: userinfo.GetUserIcon(),
  345. IsAdmin: userinfo.IsAdmin(),
  346. UserGroups: pgs,
  347. StorageQuotaTotal: userinfo.StorageQuota.GetUserStorageQuota(),
  348. StorageQuotaLeft: remainingQuota,
  349. }
  350. if noicon {
  351. rs.UserIcon = ""
  352. }
  353. jsonString, _ := json.Marshal(rs)
  354. utils.SendJSONResponse(w, string(jsonString))
  355. }
  356. //Icon handling function for web endpoint
  357. func desktop_fileLocation_handler(w http.ResponseWriter, r *http.Request) {
  358. get, _ := utils.Mv(r, "get", true) //Check if there are get request for a given filepath
  359. set, _ := utils.Mv(r, "set", true) //Check if there are any set request for a given filepath
  360. del, _ := utils.Mv(r, "del", true) //Delete the given filename coordinate
  361. if set != "" {
  362. //Set location with given paramter
  363. x := 0
  364. y := 0
  365. sx, _ := utils.Mv(r, "x", true)
  366. sy, _ := utils.Mv(r, "y", true)
  367. path := set
  368. x, err := strconv.Atoi(sx)
  369. if err != nil {
  370. x = 0
  371. }
  372. y, err = strconv.Atoi(sy)
  373. if err != nil {
  374. y = 0
  375. }
  376. //Set location of icon from path
  377. username, _ := authAgent.GetUserName(w, r)
  378. err = setDesktopLocationFromPath(path, username, x, y)
  379. if err != nil {
  380. utils.SendErrorResponse(w, err.Error())
  381. return
  382. }
  383. utils.SendJSONResponse(w, string("\"OK\""))
  384. } else if get != "" {
  385. username, _ := authAgent.GetUserName(w, r)
  386. x, y, _ := getDesktopLocatioFromPath(get, username)
  387. result := []int{x, y}
  388. json_string, _ := json.Marshal(result)
  389. utils.SendJSONResponse(w, string(json_string))
  390. } else if del != "" {
  391. username, _ := authAgent.GetUserName(w, r)
  392. delDesktopLocationFromPath(del, username)
  393. } else {
  394. //No argument has been set
  395. utils.SendJSONResponse(w, "Paramter missing.")
  396. }
  397. }
  398. //////////////////////////////// END OF DESKTOP FILE ICON HANDLER ///////////////////////////////////////////////////
  399. func desktop_theme_handler(w http.ResponseWriter, r *http.Request) {
  400. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  401. if err != nil {
  402. utils.SendErrorResponse(w, "User not logged in")
  403. return
  404. }
  405. username := userinfo.Username
  406. //Check if the set GET paramter is set.
  407. targetTheme, _ := utils.Mv(r, "set", false)
  408. getUserTheme, _ := utils.Mv(r, "get", false)
  409. loadUserTheme, _ := utils.Mv(r, "load", false)
  410. if targetTheme == "" && getUserTheme == "" && loadUserTheme == "" {
  411. //List all the currnet themes in the list
  412. themes, err := filepath.Glob("web/img/desktop/bg/*")
  413. if err != nil {
  414. log.Println("[Desktop] Unable to search bg from destkop image root. Are you sure the web data folder exists?")
  415. return
  416. }
  417. //Prase the results to json array
  418. //Tips: You must use captial letter for varable in struct that is accessable as public :)
  419. type desktopTheme struct {
  420. Theme string
  421. Bglist []string
  422. }
  423. var desktopThemeList []desktopTheme
  424. acceptBGFormats := []string{
  425. ".jpg",
  426. ".png",
  427. ".gif",
  428. }
  429. for _, file := range themes {
  430. if fs.IsDir(file) {
  431. thisTheme := new(desktopTheme)
  432. thisTheme.Theme = filepath.Base(file)
  433. bglist, _ := filepath.Glob(file + "/*")
  434. var thisbglist []string
  435. for _, bg := range bglist {
  436. ext := filepath.Ext(bg)
  437. //if (sliceutil.Contains(acceptBGFormats, ext) ){
  438. if utils.StringInArray(acceptBGFormats, ext) {
  439. //This file extension is supported
  440. thisbglist = append(thisbglist, filepath.Base(bg))
  441. }
  442. }
  443. thisTheme.Bglist = thisbglist
  444. desktopThemeList = append(desktopThemeList, *thisTheme)
  445. }
  446. }
  447. //Return the results as JSON string
  448. jsonString, err := json.Marshal(desktopThemeList)
  449. if err != nil {
  450. log.Println("[Desktop] Marshal desktop wallpaper list error: " + err.Error())
  451. utils.SendJSONResponse(w, string("[]"))
  452. return
  453. }
  454. utils.SendJSONResponse(w, string(jsonString))
  455. return
  456. } else if getUserTheme == "true" {
  457. //Get the user's theme from database
  458. result := ""
  459. sysdb.Read("desktop", username+"/theme", &result)
  460. if result == "" {
  461. //This user has not set a theme yet. Use default
  462. utils.SendJSONResponse(w, string("\"default\""))
  463. return
  464. } else {
  465. //This user already set a theme. Use its set theme
  466. utils.SendJSONResponse(w, string("\""+result+"\""))
  467. return
  468. }
  469. } else if loadUserTheme != "" {
  470. //Load user theme base on folder path
  471. userFsh, err := GetFsHandlerByUUID("user:/")
  472. if err != nil {
  473. utils.SendErrorResponse(w, "Unable to resolve user root path")
  474. return
  475. }
  476. userFshAbs := userFsh.FileSystemAbstraction
  477. rpath, err := userFshAbs.VirtualPathToRealPath(loadUserTheme, userinfo.Username)
  478. if err != nil {
  479. utils.SendErrorResponse(w, "Custom folder load failed")
  480. return
  481. }
  482. //Check if the folder exists
  483. if !userFshAbs.FileExists(rpath) {
  484. utils.SendErrorResponse(w, "Custom folder load failed")
  485. return
  486. }
  487. if userinfo.CanRead(loadUserTheme) == false {
  488. //No read permission
  489. utils.SendErrorResponse(w, "Permission denied")
  490. return
  491. }
  492. //Scan for jpg, gif or png
  493. imageList := []string{}
  494. scanPath := filepath.ToSlash(filepath.Clean(rpath)) + "/"
  495. pngFiles, _ := filepath.Glob(scanPath + "*.png")
  496. jpgFiles, _ := filepath.Glob(scanPath + "*.jpg")
  497. gifFiles, _ := filepath.Glob(scanPath + "*.gif")
  498. //Merge all 3 slice into one image list
  499. imageList = append(imageList, pngFiles...)
  500. imageList = append(imageList, jpgFiles...)
  501. imageList = append(imageList, gifFiles...)
  502. //Convert the image list back to vpaths
  503. virtualImageList := []string{}
  504. for _, image := range imageList {
  505. vpath, err := userFshAbs.RealPathToVirtualPath(image, userinfo.Username)
  506. if err != nil {
  507. continue
  508. }
  509. virtualImageList = append(virtualImageList, vpath)
  510. }
  511. js, _ := json.Marshal(virtualImageList)
  512. utils.SendJSONResponse(w, string(js))
  513. } else if targetTheme != "" {
  514. //Set the current user theme
  515. sysdb.Write("desktop", username+"/theme", targetTheme)
  516. utils.SendJSONResponse(w, "\"OK\"")
  517. return
  518. }
  519. }
  520. func desktop_preference_handler(w http.ResponseWriter, r *http.Request) {
  521. preferenceType, _ := utils.Mv(r, "preference", true)
  522. value, _ := utils.Mv(r, "value", true)
  523. remove, _ := utils.Mv(r, "remove", true)
  524. username, err := authAgent.GetUserName(w, r)
  525. if err != nil {
  526. //user not logged in. Redirect to login page.
  527. utils.SendErrorResponse(w, "User not logged in")
  528. return
  529. }
  530. if preferenceType == "" && value == "" {
  531. //Invalid options. Return error reply.
  532. utils.SendErrorResponse(w, "Error. Undefined paramter.")
  533. return
  534. } else if preferenceType != "" && value == "" && remove == "" {
  535. //Getting config from the key.
  536. result := ""
  537. sysdb.Read("desktop", username+"/preference/"+preferenceType, &result)
  538. jsonString, _ := json.Marshal(result)
  539. utils.SendJSONResponse(w, string(jsonString))
  540. return
  541. } else if preferenceType != "" && value == "" && remove == "true" {
  542. //Remove mode
  543. sysdb.Delete("desktop", username+"/preference/"+preferenceType)
  544. utils.SendOK(w)
  545. return
  546. } else if preferenceType != "" && value != "" {
  547. //Setting config from the key
  548. sysdb.Write("desktop", username+"/preference/"+preferenceType, value)
  549. utils.SendOK(w)
  550. return
  551. } else {
  552. utils.SendErrorResponse(w, "Error. Undefined paramter.")
  553. return
  554. }
  555. }
  556. func desktop_shortcutHandler(w http.ResponseWriter, r *http.Request) {
  557. userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
  558. if err != nil {
  559. //user not logged in. Redirect to login page.
  560. utils.SendErrorResponse(w, "User not logged in")
  561. return
  562. }
  563. shortcutType, err := utils.Mv(r, "stype", true)
  564. if err != nil {
  565. utils.SendErrorResponse(w, err.Error())
  566. return
  567. }
  568. shortcutText, err := utils.Mv(r, "stext", true)
  569. if err != nil {
  570. utils.SendErrorResponse(w, err.Error())
  571. return
  572. }
  573. shortcutPath, err := utils.Mv(r, "spath", true)
  574. if err != nil {
  575. utils.SendErrorResponse(w, err.Error())
  576. return
  577. }
  578. shortcutIcon, err := utils.Mv(r, "sicon", true)
  579. if err != nil {
  580. utils.SendErrorResponse(w, err.Error())
  581. return
  582. }
  583. shortcutCreationDest, err := utils.Mv(r, "sdest", true)
  584. if err != nil {
  585. //Default create on desktop
  586. shortcutCreationDest = "user:/Desktop/"
  587. }
  588. if !userinfo.CanWrite(shortcutCreationDest) {
  589. utils.SendErrorResponse(w, "Permission denied")
  590. return
  591. }
  592. //Resolve vpath to fsh and subpath
  593. fsh, subpath, err := GetFSHandlerSubpathFromVpath(shortcutCreationDest)
  594. if err != nil {
  595. utils.SendErrorResponse(w, err.Error())
  596. return
  597. }
  598. fshAbs := fsh.FileSystemAbstraction
  599. shorcutRealDest, err := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
  600. if err != nil {
  601. utils.SendErrorResponse(w, err.Error())
  602. return
  603. }
  604. //Filter illegal characters in the shortcut filename
  605. shortcutText = arozfs.FilterIllegalCharInFilename(shortcutText, " ")
  606. //If dest not exists, create it
  607. if !fshAbs.FileExists(shorcutRealDest) {
  608. fshAbs.MkdirAll(shorcutRealDest, 0755)
  609. }
  610. //Generate a filename for the shortcut
  611. shortcutFilename := shorcutRealDest + "/" + shortcutText + ".shortcut"
  612. counter := 1
  613. for fshAbs.FileExists(shortcutFilename) {
  614. shortcutFilename = shorcutRealDest + "/" + shortcutText + "(" + strconv.Itoa(counter) + ")" + ".shortcut"
  615. counter++
  616. }
  617. //Write the shortcut to file
  618. shortcutContent := shortcut.GenerateShortcutBytes(shortcutPath, shortcutType, shortcutText, shortcutIcon)
  619. err = fshAbs.WriteFile(shortcutFilename, shortcutContent, 0775)
  620. if err != nil {
  621. utils.SendErrorResponse(w, err.Error())
  622. return
  623. }
  624. utils.SendOK(w)
  625. }