plain.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. # -*- coding: utf-8 -*-
  2. #
  3. # This file is part of Radicale Server - Calendar Server
  4. # Copyright © 2008-2010 Guillaume Ayoub
  5. # Copyright © 2008 Nicolas Kandel
  6. # Copyright © 2008 Pascal Halter
  7. #
  8. # This library is free software: you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation, either version 3 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This library is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with Radicale. If not, see <http://www.gnu.org/licenses/>.
  20. """
  21. Plain text storage.
  22. """
  23. import os
  24. import posixpath
  25. import codecs
  26. from radicale import config, ical
  27. FOLDER = os.path.expanduser(config.get("support", "folder"))
  28. DEFAULT_CALENDAR = config.get("support", "calendar")
  29. def _open(path, mode="r"):
  30. """Open file at ``path`` with ``mode``, automagically managing encoding."""
  31. return codecs.open(path, mode, config.get("encoding", "stock"))
  32. def calendars():
  33. """List available calendars paths."""
  34. available_calendars = []
  35. for filename in os.listdir(FOLDER):
  36. if os.path.isdir(os.path.join(FOLDER, filename)):
  37. for cal in os.listdir(os.path.join(FOLDER, filename)):
  38. available_calendars.append(posixpath.join(filename, cal))
  39. return available_calendars
  40. def mkcalendar(name):
  41. """Write a new calendar called ``name``."""
  42. user, cal = name.split(posixpath.sep)
  43. if not os.path.exists(os.path.join(FOLDER, user)):
  44. os.makedirs(os.path.join(FOLDER, user))
  45. descriptor = _open(os.path.join(FOLDER, user, cal), "w")
  46. descriptor.write(ical.write_calendar())
  47. def read(cal):
  48. """Read calendar ``cal``."""
  49. path = os.path.join(FOLDER, cal.replace(posixpath.sep, os.path.sep))
  50. return _open(path).read()
  51. def append(cal, vcalendar):
  52. """Append ``vcalendar`` to ``cal``."""
  53. old_calendar = read(cal)
  54. old_timezones = [timezone.id for timezone in ical.timezones(old_calendar)]
  55. path = os.path.join(FOLDER, cal.replace(posixpath.sep, os.path.sep))
  56. old_objects = []
  57. old_objects.extend([event.etag for event in ical.events(old_calendar)])
  58. old_objects.extend([todo.etag for todo in ical.todos(old_calendar)])
  59. objects = []
  60. objects.extend(ical.events(vcalendar))
  61. objects.extend(ical.todos(vcalendar))
  62. for timezone in ical.timezones(vcalendar):
  63. if timezone.id not in old_timezones:
  64. descriptor = _open(path)
  65. lines = [line for line in descriptor.readlines() if line]
  66. descriptor.close()
  67. for i, line in enumerate(timezone.text.splitlines()):
  68. lines.insert(2 + i, line + "\n")
  69. descriptor = _open(path, "w")
  70. descriptor.writelines(lines)
  71. descriptor.close()
  72. for obj in objects:
  73. if obj.etag not in old_objects:
  74. descriptor = _open(path)
  75. lines = [line for line in descriptor.readlines() if line]
  76. descriptor.close()
  77. for line in obj.text.splitlines():
  78. lines.insert(-1, line + "\n")
  79. descriptor = _open(path, "w")
  80. descriptor.writelines(lines)
  81. descriptor.close()
  82. def remove(cal, etag):
  83. """Remove object named ``etag`` from ``cal``."""
  84. path = os.path.join(FOLDER, cal.replace(posixpath.sep, os.path.sep))
  85. cal = read(cal)
  86. headers = ical.headers(cal)
  87. timezones = ical.timezones(cal)
  88. todos = [todo for todo in ical.todos(cal) if todo.etag != etag]
  89. events = [event for event in ical.events(cal) if event.etag != etag]
  90. descriptor = _open(path, "w")
  91. descriptor.write(ical.write_calendar(headers, timezones, todos, events))
  92. descriptor.close()
  93. # Create default calendar if not present
  94. if DEFAULT_CALENDAR:
  95. if DEFAULT_CALENDAR not in calendars():
  96. mkcalendar(DEFAULT_CALENDAR)