desktop.go 23 KB

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